nezumi-lab
January 7th, 2009, 16:28
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, 0×3). 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 ("http://nezumi-lab.org/ffh/endbl_trace_demo.zip")it and run. the output should look like this:
http://nezumi-lab.org/blog/?p=37
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, 0×3). 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 ("http://nezumi-lab.org/ffh/endbl_trace_demo.zip")it and run. the output should look like this:
IDA says breakpoint:did you see this? IDA-Pro stops at every calls!!! so, the final version of the correct tracer should look like this:
00402CECh:call ds:HeapFree
00402CEChop esi
IDA says breakpoint:
00401AC4h:call _calloc
00401AC4hop ecx
IDA says breakpoint:
00401067h:call _printf
00401067h:add esp, 10h
4010B0: hit breakpoint
heuristic says breakpoint!
// start tracing
EnableTracing(TRACE_XA, 1);
// wait for any debug even
code = GetDebuggerEvent(WFNE_ANY | WFNE_CONT, MAX_WAIT);
while(1)
{
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";
break;
}
// 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);
}
http://nezumi-lab.org/blog/?p=37