IDAPython conditional breakpoints or ‘QuickHooking with IDAPython’

Conditional breakpoints

Conditional breakpoints. Ohh beloved conditional breakpoints! Everybody loves conditional breakpoints. They allows us to wait at a certain moment to stop, sparing us a lot of tedious manual tracing. There isn’t anything easier and more gratifying that hooking our process’ code by just setting a breakpoint, typing some lines, and looking our process stopped right there, when the fun starts. Nowadays, almost every decent debugger counts with hardware breakpoints. Some of them with very flexibles interfaces and some others with very limited ones. In fact, this is a crucial point when deciding the limit between a complex hardware breakpoint and the use of a debugging library/tool that allows us to have full control of the context to programatically manipulate the process execution as we need. When talking about IDA, we can say that it has a very flexible interface because it allows us to define the breakpoint conditions using the IDC scripting language. It’s mostly used to express very simple conditions like EAX == 0x1 or to do little memory modifications. But, as an IDAPython fan, I’ve always wanted to be able to use IDAPython when handling my quick conditional breakpoints. Thinking on this and with the help of some friends i managed to get a way to reuse the tip I’ve previously shared with you here. The idea behind this post is to take advantage of the posibilities of using IDC in conditional breakpoints to define an IDC function that will execute and evaluate an IDAPython function. To demonstrate this I’ve made a very simple script called conditional_plugin.pythat can be used as a template for more elaborated scripts. Let’s see the code. It’s divided in two main parts: The one in charge of setting a breakpoint in a desired address, and one in charge of the handling of it.

def set_bp(address, cnd):

 global cond_file

 print "[+] Setting conditional IDAPython breakpoint on %08x" % address

 add_bpt(address, 0, BPT_SOFT)
 enable_bpt(address, True)
 SetBptCnd(address, cnd)

idaapi.CompileLine('static cond() {return (RunPythonStatement("condition()") | Byte(0x10000));}')
set_bp(ScreenEA(), 'cond()')

We can clearly see that set_bp only sets a breakpoint (in this example, a software breakpoint), enables it, and defines a condition for it. The next two lines are very similar to this. There is a small caveat with this technique but we’ll talk about the particularities of this case later. By now, we’ll just take care of: 1 – Define the IDC function “func()” that will be in charge through RunPythonStatement of calling our Python function “condition()“. 2 – Set cond()as breakpoint condition Then we have the IDAPython condition itself:

def condition():
...

 # Condition
 eax = GetRegValue("EAX")
 if eax != 0x0:
 print "[+] Condition met"
 BREAK()
 else:
 CONTINUE()

It’s in this function where we’ll be doing the IDAPython magic to handle our breakpoint. In this example we’ll just get the EAX value to compare it with an specific value. If the condition is met, we’ll call BREAK() to stop the process execution. Otherwise, we’ll call CONTINUE()to continue with the normal execution. Let’s see this two functions

CONTINUE = lambda: PatchByte(0x10000,0)
BREAK = lambda: PatchByte(0x10000,1)

These are just some DEFINE-like lines to get rid of the problem i’ve mentioned before. RunPythonStatement always returns 0. As there is no way to obtain a value sent from python I chose to use a byte from the process memory space as a global variable through IDC and IDAPython. Probably there are better solutions to this issue out there. I must admit didn’t search enough. Anyway, if somebody has a better idea, I’ll be glad to hear about it🙂 Here, we’ll simply use PatchByte()to put 0 or 1 at address 0x10000, the memory address used by every process to hold the environment variables. This explains the line that defines the cond() function:

idaapi.CompileLine('static cond() {return (RunPythonStatement("condition()") | Byte(0x10000));}')

It’s just a dirty way to keep it a oneliner: RunPythonStatement always returns 0, so Byte(0x10000) is what really matters. that way cond() will return 0 or 1 depending on which function (CONTINUE or BREAK) we called. So, there you have it! A quick ‘n dirty way to programaticaly handle breakpoints with IDAPython. Of course, this is obviously just a basic example. Based in this template we can implement a lot of different techniques like memory tracking, function monitoring, process patching, bypasses of anti debugging methods, code injection, and much more fun! If my laziness doesn’t stop me -as it usually does- I will try to put together a few scripts I’ve made to offer you a few different starting-points. See ya!

~ by aLS -- on June 29, 2010.

4 Responses to “IDAPython conditional breakpoints or ‘QuickHooking with IDAPython’”

  1. Hi,

    You don’t need to do this hack.

    Simply enable IDAPython as the current extlang and conditional breakpoints will be evaluated using Python:

    At some point type (say before you start debugging) this IDC expression: RunPlugin(“python”, 3) to enable Python extlang.

    Not only bp conditions will be evaluated using Python, almost all input fields will now accept Python statements.

  2. Oohhh dude! I’d have liked to know this before…

    Anyway. Great tip. I’ll try to update the post soon.
    Thank you.

  3. You just had to ask!🙂

  4. great!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: