looks like IDA Pro 5.3 has another bug. EnableTracing()/GetDebuggerEvent(WFNE_ANY, -1); returns 10h (BREAKPOINT) on function calls thanks to internal IDA-Pro breakpoints. IDA-Pro sets breakpoints after calls to perform step over tracing (TRACE_FUNC). Soft-Ice and OllyDbg do the same thing. the problem is - EnableTracing() does it every time, even we ask it for TRACE_STEP or TRACE_INSN. IDA-Pro should hide internal breakpoints, but she forgets to do it!

not good for us! well, how we’re going to handle this? um, r_eip = GetEventEa() points to the next instruction after the call and GetBptAttr(r_eip, BPTATTR_EA) = = -1, where -1 means no breakpoint here. why? coz, GetBptAttr() hides internal breakpoints, but EnableTracing() does not. so, it’s definitely a bug. normally, debuggers always hides internal breakpoints - nobody wants to confuse users. well, IDA-Pro does.

another bug: a real breakpoint just freezes IDA-Pro and GetDebuggerEvent(WFNE_ANY, -1) will never return, so we have to specify the second argument (time to wait), calling the function like this: GetDebuggerEvent(WFNE_ANY, 03). of course, if GetDebuggerEvent() returns DBG_TIMEOUT we have to check for real breakpoints. if GetBptAttr(r_eip, BPTATTR_EA) = = r_eip it means that a real breakpoint is here. it’s a simple heuristic algorithm, but it works!

I wrote a simple script to demonstrate how to use EnableTracing(). download it and run. the output should look like this:

IDA says breakpoint:
00402CECh:call ds:HeapFree
00402CECh:pop esi

IDA says breakpoint:
00401AC4h:call _calloc
00401AC4h:pop ecx

IDA says breakpoint:
00401067h:call _printf
00401067h:add esp, 10h

4010B0: hit breakpoint
heuristic says breakpoint!
did you see this? IDA-Pro stops at every calls!!! so, the final version of the correct tracer should look like this:

// start tracing
EnableTracing(TRACE_XA, 1);

// wait for any debug even
code = GetDebuggerEvent(WFNE_ANY | WFNE_CONT, MAX_WAIT);

r_eip = GetEventEa(); // next even eip

if (code == BREAKPOINT) // <<< IDA BUG!!!
Message("IDA says breakpoint:\n%08Xh:%s\n%08Xh:%s\n\n",
r_eip, GetDisasm(PrevHead(r_eip, 0)), r_eip, GetDisasm(r_eip) );

if (code == DBG_TIMEOUT) // exit due to timeout
// check for breakpoints
if (GetBptAttr(r_eip, BPTATTR_EA) == r_eip) // real bp
Message("heuristic says breakpoint!\n");


// check for errors
if (code < 1) break;

// wait for a next event
// MAX_WAIT (time to wait, sec) - prevents IDA freezing
code = GetDebuggerEvent(WFNE_ANY, MAX_WAIT);