TippingPoint Digital Vaccine Laboratories
DID YOU KNOW... In December of 2007, Microsoft released seven security bulletins which fixed 11 new security vulnerabilities. TippingPoint and ZDI were credited with discovering a total of four of those vulnerabilities.

MindshaRE: Utilizing PyDbg Within IDA

Previously on MindshaRE we have demonstrated using PyDbg as a companion to IDA. Today I wanted to demonstrate how to use PyDbg from within IDA. With the power of IDA, IDAPython, and PyDbg you can create powerful tools that are extremely helpful when reverse engineering.

MindshaRE is our weekly look at some simple reverse engineering tips and tricks. The goal is to keep things small and discuss every day aspects of reversing. You can view previous entries here by going through our blog history.

If you aren't familiar with PyDbg you need to read this, this, this, and this. PyDbg, which is included in PaiMei, allows the user to create fully functional debugging scripts in Python.

When we combine the flexibility of PyDbg with the comprehensiveness of IDAPython there really is no limit to what you can do. In today's example I am going to show you how to get started with the very basics. Our goal will be to set a breakpoint based on the current location in IDA, launch or attach to the executable being disassembled, and dump its register state when the breakpoint is hit.

First we are going to gather all the information we need from IDA. This will include the current address, and name of the executable being disassembled.
# IDC Functions
ea = ScreenEA()
process = GetInputFile()
The ScreenEA() function returns the current address that your cursor is at in the IDA window. GetInputFile() returns the name of the file being disassembled including its extension. Now let's look at a few of the PyDbg methods.
# PyDbg Functions
dbg = pydbg()
dbg.ida_ea = ea
dbg.process = process
dbg.set_callback(EXCEPTION_BREAKPOINT, breakpoint_handler)
Here we have created an instance of the debugger, and set up a callback for breakpoints when they are encountered.

Next we simply load, or attach to the process.
def attach_target_proc(dbg, procname):
    imagename = procname.rsplit('\\')[-1]
    print "[*] Trying to attach to existing %s" % imagename
    for (pid, name) in dbg.enumerate_processes():
        if imagename in name.lower():
                print "[*] Attaching to %s (%d)" % (name, pid)
                print "[!] Problem attaching to %s" % name
                return False
            return True
        print "[*] Trying to load %s" % (procname)
        dbg.load(procname, "")
        print "[!] Problem loading %s" % (procname)
        return False
    return True

if attach_target_proc(dbg, process):
    print "[!] Couldn't load/attach to %s" % process
This piece of code will attach or load the process under the dbg instance we previously instantiated. Since we have set a breakpoint handler lets look at what that will do when hit.
def breakpoint_handler(dbg):
    # Initial module bp
    if dbg.first_breakpoint:
        # Set IDA BP
        dbg.bp_set(dbg.ida_ea, restore=False)
        return DBG_CONTINUE

    return DBG_CONTINUE
Here we see the setting of our current location in IDA. Once the breakpoint is set, execution resumes in the target process until the bp is hit. When the breakpoint is hit we will execute the print_state() function. This function dumps our register state as you would see in WinDbg.

When we run this from IDA we can see the following output.

.text:01012314 mulnumx proc near
.text:01012314 arg_0    = dword ptr  8
.text:01012314 arg_4    = dword ptr  0Ch
.text:01012314          push    ebp
.text:01012315          mov     ebp, esp
.text:01012317          push    esi


[*] Trying to attach to existing calc.exe
[*] Trying to load calc.exe

eax=00000000 ebx=00000020 ecx=000aa440 edx=0000000a esi=000aa410 edi=01014fe8
eip=01012314 esp=0007fd98 ebp=0007fdc0

calc.exe!01012314  push ebp
As you can see this is a very handy way to call a process and dump state information at a location you are interested in. Even though this is a simple example it should help lay the foundation for more complex scripts you dream up. The full version of the above script can be found here: ida_pydbg.py.

Before we wrap this up, there are a few things to keep in mind when running scripts from within IDA. IDA, and IDAPython are run under the same thread. This means if your script is blocking due to the debugger event loop, the IDA UI will also be blocking. Because of this you cannot run the debugger and work in IDA concurrently. This limitation will also prevent you from logging messages in the IDA window, or interacting with the IDAPython script. Try and limit script output until the end, and ensure you display it in a manner suitable for IDA's log window.

With all of this in mind next time you find yourself needing some debugger help, try and utilize the very powerful IDAPython and PyDbg libraries.

Published On: 2008-11-20 12:38:30

Comments post a comment

  1. Dima commented on 2008-11-20 @ 21:55

    Why not the built in debugger? As far as i know IdaPython covers all the debugging features of IDA. That kind of script is not gonna block IDA while it's running. Beside that if we are dealing with a dynamic library it may have different image base then it has in IDA which may cause some problems as well.

  2. Cody Pierce commented on 2008-11-24 @ 08:50

    @Dima: The IDA debugger will work just as well. I am discussing one option out of many. Also, a benefit of learning and using PyDbg is its ability to be used outside of IDA.

Links To This Post

  1. Interesting Information Security Bits for 11/21/2008 at Infosec Ramblings
    linked on 2008-11-21 @ 13:56 Show Comment

    Ever wanted to be able to us PyDbg from within IDA. Cody of over at DVLabs is here to show you how. Trackback