Repository URL to install this package:
Version:
9.1~250226-1.fc43 ▾
|
"""
summary: react to trace notifications
description:
This script demonstrates using the low-level tracing hook
(ida_dbg.DBG_Hooks.dbg_trace). It can be run like so:
ida.exe -B -Sdbg_trace.py -Ltrace.log file.exe
level: advanced
"""
import time
import ida_dbg
import ida_ida
import ida_pro
import ida_ua
from ida_allins import NN_callni, NN_call, NN_callfi
from ida_lines import generate_disasm_line, GENDSM_FORCE_CODE, GENDSM_REMOVE_TAGS
# Note: this try/except block below is just there to
# let us (at Hex-Rays) test this script in various
# situations.
try:
import idc
print(idc.ARGV[1])
under_test = bool(idc.ARGV[1])
except:
under_test = False
class TraceHook(ida_dbg.DBG_Hooks):
def __init__(self):
ida_dbg.DBG_Hooks.__init__(self)
self.traces = 0
self.epReached = False
def _log(self, msg):
print(">>> %s" % msg)
def dbg_trace(self, tid, ea):
# Log all traced addresses
if ea < ida_ida.inf_get_min_ea() or ea > ida_ida.inf_get_max_ea():
raise Exception(
"Received a trace callback for an address outside this database!"
)
self._log("trace %08X" % ea)
self.traces += 1
insn = ida_ua.insn_t()
insnlen = ida_ua.decode_insn(insn, ea)
# log disassembly and ESP for call instructions
if insnlen > 0 and insn.itype in [NN_callni, NN_call, NN_callfi]:
self._log(
"call insn: %s"
% generate_disasm_line(ea, GENDSM_FORCE_CODE | GENDSM_REMOVE_TAGS)
)
self._log("ESP=%08X" % ida_dbg.get_reg_val("ESP"))
return 1
def dbg_run_to(self, pid, tid=0, ea=0):
# this hook is called once execution reaches temporary breakpoint set by run_to(ep) below
if not self.epReached:
ida_dbg.refresh_debugger_memory()
self._log("reached entry point at 0x%X" % ida_dbg.get_reg_val("EIP"))
self._log("current step trace options: %x" % ida_dbg.get_step_trace_options())
self.epReached = True
# enable step tracing (single-step the program and generate dbg_trace events)
ida_dbg.request_enable_step_trace(1)
# change options to only "over debugger segments" (i.e. library functions will be traced)
ida_dbg.request_set_step_trace_options(ida_dbg.ST_OVER_DEBUG_SEG)
ida_dbg.request_continue_process()
ida_dbg.run_requests()
def dbg_process_exit(self, pid, tid, ea, code):
self._log("process exited with %d" % code)
self._log("traced %d instructions" % self.traces)
return 0
def do_trace(then_quit_ida=True):
debugHook = TraceHook()
debugHook.hook()
# Start tracing when entry point is hit
ep = ida_ida.inf_get_start_ip()
ida_dbg.enable_step_trace(1)
ida_dbg.set_step_trace_options(ida_dbg.ST_OVER_DEBUG_SEG | ida_dbg.ST_OVER_LIB_FUNC)
print("Running to %x" % ep)
ida_dbg.run_to(ep)
while ida_dbg.get_process_state() != 0:
ida_dbg.wait_for_next_event(1, 0)
if not debugHook.epReached:
raise Exception("Entry point wasn't reached!")
if not debugHook.unhook():
raise Exception("Error uninstalling hooks!")
del debugHook
if then_quit_ida:
# we're done; exit IDA
ida_pro.qexit(0)
# load the debugger module depending on the file type
if ida_ida.inf_get_filetype() == ida_ida.f_PE:
ida_dbg.load_debugger("win32", 0)
elif ida_ida.inf_get_filetype() == ida_ida.f_ELF:
ida_dbg.load_debugger("linux", 0)
elif ida_ida.inf_get_filetype() == ida_ida.f_MACHO:
ida_dbg.load_debugger("mac", 0)
if not under_test:
do_trace()