IDA python over IPC
Author: David Zimmer
Date: 11.08.17 - 3:58am
Continuing on from a previous thought about IDASRVR and x64 IDA7.
Everytime I want a new command in IDASRVR i need to find the functionality in the C API, then write a new stub to make it accessible over my IPC mechanism. Its no surprise I have only implemented what I have needed as I have needed it.
The IDA Python API wraps a zillion more things than I have, can I just have my C IPC server call the python api and then pass me back the return value?
Thought two, with the differences between the C API and compile requirements between IDA 6.95 and IDA 7 and also between 32bit and 64bit databases do I even want to deal with the C API anymore. Can I just host the entire IPC server in python as a .py plugin?
I have been experimenting with both of these things.
The python IPC server was pretty straight forward to create. I use the same WM_COPYDATA mechanism as IDASRVR. This lets clients broadcast to enumerate all open server windows, is by default synchronous across processes and has a built in timeout I dont have to worry about. Even through its local and windows only its just the way to go for my needs. Only downside is you have to manually start it when you want to use it although this could be overcome I am sure.
So basically it listens on a hwnd, when a command comes in it uses python exec or eval to run it. Script output is returned to the IPC client through a reply() function.
Ok cool. Now what about the C IDASRVR plugin. Can I run arbitrary python commands from that? The answer again is yes.
I did a little digging and found a hexblog post that got me started. I had experimented with python embedding a little bit, so now I got to play some more.
One thing i noticed when embedding Python within an IDA plugin... IDA links against the python27.dll always. When i compiled my plugin in debug mode it would fail to load, but release mode was ok. It didnt matter which lib i linked against (python27_d.lib or python27.lib).
Turns out python.h has a little hidden surprise
#include python.h -> pyconfig.h -> ifdef _DEBUG pragma comment(lib,"python27_d.lib") The solution is: #ifdef _DEBUG #undef _DEBUG #include python27/Python.h #define _DEBUG #else #include python27/Python.h #endifNow when we receive a python command over IPC
In order to return values back to our IPC client again we add a reply() function called from the script itself. Two caveats here:
Now the client scripts can just simply call reply(). You can also see the hPyClient respond to hwnd has also been cached by the C code for simplicity.
So anyway..it works and it was pretty easy to implement. I still need to bench mark it to see how much of a hit I am taking. I am sure it will be slow, but It will be nice to have as a fall back for API i havent implemented in C yet. At the end of the day I am just one dude tinkering on what I need. One of the things I need is the ability to leverage other peoples work so here it is in all of its lazy sloppy glory! *
I have added support for the pycmd handler in IDASRVR. The vb6 demo project has support for it already and it is as simple to use as the following:
resp = ida.pythonTest("reply('A'*1001)")
*This feels a little sloppy and slow, but I only have limited time and just need to get things done plus python is already loaded and installed with IDA. End of the day the C embedding was implemented in 60 lines of code, less than two hours time, and makes hundreds of new API available to me at zero additional cost. You cant ignore leverage like that.