Binary Ninja: IPython and the Python Console

Binary Ninja is the new hotness in the reverse engineering world. It represents a new age of beautiful, programmatic reverse engineering. It's clear that if the IDA Disassembler is going to be the IDE of reversing, then Binary Ninja (or binja as most people call it) wants to be the Sublime Text or Atom text editor of reversing.

I've played with binja a bit and here are some things I've figured out that help me when working with it.

Virtual Environments

Virtual Environments are great, they help you keep your Python modules organized and even let you switch Python versions pretty easily.

If you have the commercial license and leverage the scripting interface it may help to install the binaryninja module in a virtualenv.

You can do that with the following commands with virtualenvwrapper.

mkvirtualenv binja
add2virtualenv '/Applications/Binary Ninja.app/Contents/Resources/python'
workon binja

All of a sudden you're that much more organized!

IPython and Tab Complete

The binja Python console is a vanilla Python console that overrides stdin/stdout/stderr to get the Python output to show up in the binja interface.

For users of binja's commercial license there's little problem with just modifying the PYTHONPATH (like we did before with add2virtualenv) to include the binaryninja Python module and also use IPython.

If you run into issues with IPython calling sys.stdout.flush() and giving an error about _PythonScriptingInstanceOutput, keep reading.

For users of the personal license it's a little more difficult to get IPython working.

Note that right now this trick for IPython will only work on OSX

First you need to modify __init__.py to effectively break the built in Python console while you are using IPython.

OSX users can find the right file here:
/Applications/Binary Ninja.app/Contents/Resources/python/binaryninja/__init__.py

You should now apply the patch here by modifying the last few lines of __init__.py to the following code:

if not sys.stdin.isatty():
	# Wrap stdin/stdout/stderr for Python scripting provider implementation
	sys.stdin = _PythonScriptingInstanceInput(sys.stdin)
	sys.stdout = _PythonScriptingInstanceOutput(sys.stdout, False)
	sys.stderr = _PythonScriptingInstanceOutput(sys.stderr, True)

Now if you normally use Python installed via brew (as you should be doing) run:

DYLD_FRAMEWORK_PATH=/usr/local/opt/python/Frameworks /Applications/Binary\ Ninja.app/Contents/MacOS/binaryninja

Binja should open up except instead of using the built-in system Python it will now use the brew installed Python.

Now open the Python console and run:

from IPython import embed; embed()

and IPython and all its tab-complete goodness and syntax highlighting should be visible in the terminal that started binja.

Installing Python modules

If you're on OSX you can simply use DYLD_FRAMEWORK_PATH to get binja to use Brew Python and by extension, the modules installed by pip.

If you're on Windows, you should apply some patches to the __init__.py file located at

C:\Program Files\Vector35\BinaryNinja\python\binaryninja\__init__.py

By adding the flush() method to _PythonScriptingInstanceInput and _PythonScriptingInstanceOutput you increase the usability of the built in Python console.

class _PythonScriptingInstanceOutput(object):
	# ...
	def flush(self):
		pass

You may need to give your user the permission to edit C:\Program Files\Vector35\BinaryNinja\plugins\Lib\site-packages and also create C:\Program Files\Vector35\BinaryNinja\plugins\Scripts

From here you can go into the binja Python console and enter:

from setuptools.command import easy_install
easy_install.main( ["-U","requests"] )

Between module installs you may need to restart binja to get the interpreter to recognize the new modules but it should work properly if you don't have the commercial version.

If you feel like being ambitious you can install IPython through this method as well but because of the modified _PythonScriptingInstanceInput and _PythonScriptingInstanceOutput IPython is somewhat stunted and you don't get colors or the almighty tab complete so it's really not worth mentioning yet.

You can try to use pip through a similar method but I've had less success with it unless I ran it from __init__.py before the _PythonScriptingInstance* classes stole stdin/stdout/stderr away:

import pip
pip.main(['install', 'requests'])

I hope these tricks are useful to you if you use Binary Ninja.

This post was written with the help of David Manouchehri