IDAPython for IDA 7.5

This commit is contained in:
Arnaud Diederen
2020-05-27 14:34:02 +02:00
parent fc05f78e37
commit 604de9cfad
177 changed files with 102110 additions and 53038 deletions
@@ -0,0 +1,46 @@
import ida_dbg
import ida_idaapi
import ida_idd
import ida_kernwin
import ida_typeinf
import ida_name
def log(msg):
print(">>> %s" % msg)
class appcall_hooks_t(ida_dbg.DBG_Hooks):
def __init__(self, name_funcs=[]):
ida_dbg.DBG_Hooks.__init__(self) # important
for ea, func_name in name_funcs:
log("Renaming 0x%08x to \"%s\"" % (ea, func_name))
ida_name.set_name(ea, func_name)
for func_name, func_proto in [
("ref4", "int ref4(int *);"),
("ref8", "int ref8(long long int *);"),
]:
log("Setting '%s's prototype" % func_name)
func_ea = ida_name.get_name_ea(ida_idaapi.BADADDR, func_name)
assert(ida_typeinf.apply_cdecl(None, func_ea, func_proto))
def dbg_run_to(self, pid, tid, ea):
log("'run_to' reached its target location. Performing appcalls.")
for func_name in ["ref4", "ref8"]:
int_value = ida_idd.Appcall.int64(5)
int_ptr = ida_idd.Appcall.byref(int_value)
if ida_idd.Appcall[func_name](int_ptr):
log("Appcall (%s) succeeded: int_value.value=%s, int_ptr.value=%s" % (
func_name,
int_value.value,
int_ptr.value))
else:
log("Appcall (%s) failed" % func_name)
def run(self):
log("Running program up to current address, and letting the hooks do the rest")
assert(ida_dbg.run_to(ida_kernwin.get_screen_ea()))
@@ -0,0 +1,26 @@
from __future__ import print_function
#
# This sample illustrates how to use appcall, with the
# 'simple_appcall_linux32' or 'simple_appcall_linux64' test
# programs (see subdirectories.)
#
# This example will run the test program and stop wherever
# the cursor currently is, and then perform an appcall to
# `ref4` and `ref8`
#
# To use this example:
# * run `ida64` on test program `simple_appcall_linux64`, or
# `ida` on test program `simple_appcall_linux32`, and wait for
# auto-analysis to finish
# * select the 'linux debugger' (either local, or remote)
# * run this script
#
import os
import sys
sys.path.append(os.path.dirname(__file__))
import simple_appcall_common
appcall_hooks = simple_appcall_common.appcall_hooks_t()
appcall_hooks.hook()
appcall_hooks.run()
@@ -0,0 +1,42 @@
from __future__ import print_function
#
# This sample illustrates how to use appcall, with the
# 'simple_appcall_win32.exe' or 'simple_appcall_win64.exe' test
# programs (see subdirectories.)
#
# This example will run the test program and stop wherever
# the cursor currently is, and then perform an appcall to
# `ref4` and `ref8`
#
# To use this example:
# * run `ida64` on test program `simple_appcall_win64.exe`, or
# `ida` on test program `simple_appcall_win32.exe`, and wait for
# auto-analysis to finish
# * select the 'windows debugger' (either local, or remote)
# * run this script
#
import os
import sys
sys.path.append(os.path.dirname(__file__))
# Windows binaries don't have any symbols, thus we'll have
# to assign names to addresses of interest before we can
# appcall them by name.
import ida_ida
if ida_ida.inf_is_64bit():
ref4_ea = 0x140001000
ref8_ea = 0x140001060
else:
ref4_ea = 0x401000
ref8_ea = 0x401050
import simple_appcall_common
appcall_hooks = simple_appcall_common.appcall_hooks_t(
name_funcs=[
(ref4_ea, "ref4"),
(ref8_ea, "ref8"),
])
appcall_hooks.hook()
appcall_hooks.run()
@@ -0,0 +1,47 @@
ifdef __NT__
EA32_TARGET:=simple_appcall_win32.exe
EA64_TARGET:=simple_appcall_win64.exe
else
ifdef __LINUX__
EA32_TARGET:=simple_appcall_linux32
EA64_TARGET:=simple_appcall_linux64
else
$(error Not implemented for OSX)
endif
endif
all: $(EA32_TARGET) $(EA64_TARGET)
simple_appcall_win32.exe: simple_appcall_win32.obj
C:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/bin/HostX86/x86/link.exe \
/LIBPATH:C:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/lib/x86 \
/LIBPATH:C:/PROGRA~2/WI3CF2~1/10/Lib/100171~1.0/ucrt/x86 \
/LIBPATH:C:/idasrc/THIRD_~1/mssdk/8.1/Lib/x86 \
/OUT:$@ $<
simple_appcall_win32.obj: simple_appcall.c
C:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/bin/HostX86/x86/cl.exe \
/IC:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/Include \
/IC:/PROGRA~2/WI3CF2~1/10/Include/100171~1.0/ucrt \
/Zi /D__NT__ /DNDEBUG /DWIN32 /D_CONSOLE /D__VC__ /c /MD $< /Fo$@
simple_appcall_win64.exe: simple_appcall_win64.obj
C:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/bin/HostX86/x86/link.exe \
/LIBPATH:C:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/lib/x64 \
/LIBPATH:C:/PROGRA~2/WI3CF2~1/10/Lib/100171~1.0/ucrt/x64 \
/LIBPATH:C:/idasrc/THIRD_~1/mssdk/8.1/Lib/x64 \
/OUT:$@ $<
simple_appcall_win64.obj: simple_appcall.c
C:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/bin/HostX64/x64/cl.exe \
/IC:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/Include \
/IC:/PROGRA~2/WI3CF2~1/10/Include/100171~1.0/ucrt \
/Zi /D__NT__ /DNDEBUG /DWIN32 /D_CONSOLE /D__VC__ /c /MD $< /Fo$@
simple_appcall_linux32: simple_appcall.c
gcc -m32 -o $@ $<
simple_appcall_linux64: simple_appcall.c
gcc -m64 -o $@ $<
@@ -0,0 +1,35 @@
#include <stdio.h>
typedef int int32;
int ref4(int32 *a)
{
if (a == NULL)
{
printf("ref4: no number passed!");
return -1;
}
printf("ref4: entered with %d\n", *a);
(*a)++;
return 1;
}
typedef long long int int64;
int ref8(int64 *a)
{
if (a == NULL)
{
printf("ref8: no number passed!");
return -1;
}
printf("ref8: entered with %lld\n", *a);
(*a)++;
return 1;
}
int main()
{
int32 x;
int res = ref4(&x);
int64 y;
return res + ref8(&y);
}
+38 -33
View File
@@ -10,33 +10,41 @@ from __future__ import print_function
# Maintained By: IDAPython Team
#
#---------------------------------------------------------------------
from idaapi import *
class MyDbgHook(DBG_Hooks):
import ida_dbg
import ida_ida
import ida_lines
class MyDbgHook(ida_dbg.DBG_Hooks):
""" Own debug hook class that implementd the callback functions """
def __init__(self):
ida_dbg.DBG_Hooks.__init__(self) # important
self.steps = 0
def log(self, msg):
print(">>> %s" % msg)
def dbg_process_start(self, pid, tid, ea, name, base, size):
print("Process started, pid=%d tid=%d name=%s" % (pid, tid, name))
self.log("Process started, pid=%d tid=%d name=%s" % (pid, tid, name))
def dbg_process_exit(self, pid, tid, ea, code):
print("Process exited pid=%d tid=%d ea=0x%x code=%d" % (pid, tid, ea, code))
self.log("Process exited pid=%d tid=%d ea=0x%x code=%d" % (pid, tid, ea, code))
def dbg_library_unload(self, pid, tid, ea, info):
print("Library unloaded: pid=%d tid=%d ea=0x%x info=%s" % (pid, tid, ea, info))
return 0
self.log("Library unloaded: pid=%d tid=%d ea=0x%x info=%s" % (pid, tid, ea, info))
def dbg_process_attach(self, pid, tid, ea, name, base, size):
print("Process attach pid=%d tid=%d ea=0x%x name=%s base=%x size=%x" % (pid, tid, ea, name, base, size))
self.log("Process attach pid=%d tid=%d ea=0x%x name=%s base=%x size=%x" % (pid, tid, ea, name, base, size))
def dbg_process_detach(self, pid, tid, ea):
print("Process detached, pid=%d tid=%d ea=0x%x" % (pid, tid, ea))
return 0
self.log("Process detached, pid=%d tid=%d ea=0x%x" % (pid, tid, ea))
def dbg_library_load(self, pid, tid, ea, name, base, size):
print("Library loaded: pid=%d tid=%d name=%s base=%x" % (pid, tid, name, base))
self.log("Library loaded: pid=%d tid=%d name=%s base=%x" % (pid, tid, name, base))
def dbg_bpt(self, tid, ea):
print("Break point at 0x%x pid=%d" % (ea, tid))
self.log("Break point at 0x%x pid=%d" % (ea, tid))
# return values:
# -1 - to display a breakpoint warning dialog
# if the process is suspended.
@@ -45,11 +53,11 @@ class MyDbgHook(DBG_Hooks):
return 0
def dbg_suspend_process(self):
print("Process suspended")
self.log("Process suspended")
def dbg_exception(self, pid, tid, ea, exc_code, exc_can_cont, exc_ea, exc_info):
print("Exception: pid=%d tid=%d ea=0x%x exc_code=0x%x can_continue=%d exc_ea=0x%x exc_info=%s" % (
pid, tid, ea, exc_code & idaapi.BADADDR, exc_can_cont, exc_ea, exc_info))
self.log("Exception: pid=%d tid=%d ea=0x%x exc_code=0x%x can_continue=%d exc_ea=0x%x exc_info=%s" % (
pid, tid, ea, exc_code & ida_idaapi.BADADDR, exc_can_cont, exc_ea, exc_info))
# return values:
# -1 - to display an exception warning dialog
# if the process is suspended.
@@ -58,30 +66,32 @@ class MyDbgHook(DBG_Hooks):
return 0
def dbg_trace(self, tid, ea):
print("Trace tid=%d ea=0x%x" % (tid, ea))
self.log("Trace tid=%d ea=0x%x" % (tid, ea))
# return values:
# 1 - do not log this trace event;
# 0 - log it
return 0
def dbg_step_into(self):
print("Step into")
self.log("Step into")
self.dbg_step_over()
def dbg_run_to(self, pid, tid=0, ea=0):
print("Runto: tid=%d" % tid)
idaapi.continue_process()
self.log("Runto: tid=%d, ea=%x" % (tid, ea))
ida_dbg.request_step_over()
def dbg_step_over(self):
eip = get_reg_value("EIP")
print("0x%x %s" % (eip, GetDisasm(eip)))
eip = ida_dbg.get_reg_val("EIP")
disasm = ida_lines.tag_remove(
ida_lines.generate_disasm_line(
eip))
self.log("Step over: EIP=0x%x, disassembly=%s" % (eip, disasm))
self.steps += 1
if self.steps >= 5:
request_exit_process()
ida_dbg.request_exit_process()
else:
request_step_over()
ida_dbg.request_step_over()
# Remove an existing debug hook
@@ -95,14 +105,9 @@ except:
# Install the debug hook
debughook = MyDbgHook()
debughook.hook()
debughook.steps = 0
# Stop at the entry point
ep = get_inf_attr(INF_START_IP)
request_run_to(ep)
# Step one instruction
request_step_over()
# Start debugging
run_requests()
ep = ida_ida.inf_get_start_ip()
if ida_dbg.request_run_to(ep): # Request stop at entry point
ida_dbg.run_requests() # Launch process
else:
print("Impossible to prepare debugger requests. Is a debugger selected?")
+110
View File
@@ -0,0 +1,110 @@
"""
This script demonstrates using the low-level tracing hook (dbg_trace)
It can be run like: ida[t].exe -B -Sdbg_trace.py -Ltrace.log file.exe
"""
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()
@@ -0,0 +1,48 @@
import ida_dbg
import ida_idd
import ida_kernwin
import ida_ua
ACTION_NAME = "registers_context_menu:dump_reg"
class dump_reg_ah_t(ida_kernwin.action_handler_t):
def activate(self, ctx):
name = ctx.regname
value = ida_dbg.get_reg_val(name)
rtype = "integer"
rinfo = ida_idd.register_info_t()
if ida_dbg.get_dbg_reg_info(name, rinfo):
if rinfo.dtype == ida_ua.dt_byte:
value = "0x%02x" % value
elif rinfo.dtype == ida_ua.dt_word:
value = "0x%04x" % value
elif rinfo.dtype == ida_ua.dt_dword:
value = "0x%08x" % value
elif rinfo.dtype == ida_ua.dt_qword:
value = "0x%016x" % value
else:
rtype = "float"
print("> Register %s (of type %s): %s" % (name, rtype, value))
def update(self, ctx):
return ida_kernwin.AST_ENABLE_FOR_WIDGET \
if ctx.widget_type == ida_kernwin.BWN_CPUREGS \
else ida_kernwin.AST_DISABLE_FOR_WIDGET
if ida_kernwin.register_action(
ida_kernwin.action_desc_t(
ACTION_NAME,
"Dump register info",
dump_reg_ah_t())):
class registers_hooks_t(ida_kernwin.UI_Hooks):
def finish_populating_widget_popup(self, form, popup):
if ida_kernwin.get_widget_type(form) == ida_kernwin.BWN_CPUREGS:
ida_kernwin.attach_action_to_popup(form, popup, ACTION_NAME)
hooks = registers_hooks_t()
hooks.hook()
else:
print("Failed to register action")
-35
View File
@@ -1,35 +0,0 @@
from __future__ import print_function
from tempo import *;
def test_getmeminfo():
L = tempo.getmeminfo()
out = []
# start_ea end_ea name sclass sbase bitness perm
for (start_ea, end_ea, name, sclass, sbase, bitness, perm) in L:
out.append("%x: %x name=<%s> sclass=<%s> sbase=%x bitness=%2x perm=%2x" % (start_ea, end_ea, name, sclass, sbase, bitness, perm))
f = file(r"d:\temp\out.log", "w")
f.write(("\n".join(out)).encode("UTF-8"))
f.close()
print("dumped meminfo!")
def test_getregs():
# name flags class dtype bit_strings bit_strings_default_mask
L = tempo.getregs()
out = []
for (name, flags, cls, dtype, bit_strings, bit_strings_default_mask) in L:
out.append("name=<%s> flags=%x class=%x dtype=%x bit_strings_mask=%x" % (name, flags, cls, dtype, bit_strings_default_mask))
if bit_strings:
for s in bit_strings:
out.append(" %s" % s)
f = file(r"d:\temp\out.log", "w")
f.write(("\n".join(out)).encode("UTF-8"))
f.close()
print("dumped regs!")
+9 -4
View File
@@ -1,15 +1,20 @@
from __future__ import print_function
import idaapi
import ida_dbg
import ida_ida
import ida_name
def main():
if not idaapi.is_debugger_on():
if not ida_dbg.is_debugger_on():
print("Please run the process first!")
return
if idaapi.get_process_state() != -1:
if ida_dbg.get_process_state() != -1:
print("Please suspend the debugger first!")
return
dn = idaapi.get_debug_names(idaapi.cvar.inf.min_ea, idaapi.cvar.inf.max_ea)
dn = ida_name.get_debug_names(
ida_ida.inf_get_min_ea(),
ida_ida.inf_get_max_ea())
for i in dn:
print("%08x: %s" % (i, dn[i]))