Skip to content

Instantly share code, notes, and snippets.

@icecr4ck
Last active April 23, 2024 18:45
Show Gist options
  • Save icecr4ck/7a7af3277787c794c66965517199fc9c to your computer and use it in GitHub Desktop.
Save icecr4ck/7a7af3277787c794c66965517199fc9c to your computer and use it in GitHub Desktop.
Cheatsheet for IDAPython

IDAPython cheatsheet

Important links

Basic commands

Get informations on the binary

info = idaapi.get_inf_structure()
filename = idaapi.get_input_file_path()
entrypoint = info.start_ip
imagebase = ida_nalt.get_imagebase()
is_64bits = info.is_64bit()
is_dll = info.is_dll()
proc_name = ida_ida.inf_get_procname()

List adresses of the instructions

for ea in idautils.Heads():
  print(hex(ea))

Cross-references from address

for ref in idautils.XrefsTo(ea):
  print(hex(ref.frm))

Address name

idaapi.get_name(0, ea)
idaapi.get_name_ea(0, name) # name = "main" for example

for ea, name in idautils.Names():
  print("%x: %s" % (ea, name))

Read/Write bytes

# check the return value with the constant ida_idaapi.BADADDR
idaapi.get_byte(ea)
idaapi.get_bytes(ea, size)
idaapi.patch_byte(ea, byte)
idaapi.patch_bytes(ea, bytes)

Read address referenced by a pointer

def read_ptr(ea):
  if idaapi.get_inf_structure().is_64bit():
    return idaapi.get_qword(ea)
  return idaapi.get_dword(ea)

print("%x" % read_ptr(ea))

Read string

ida_bytes.get_max_strlit_length(ea, ida_nalt.STRTYPE_C)
ida_bytes.get_strlit_contents(ea, size, ida_nalt.STRTYPE_C_16)
for c in idautils.Strings()
  print s.ea, s.length, s.strtype

Get current widget

widget = idaapi.get_current_widget()
widget_type = idaapi.get_widget_type(widget) # can be any of ida_kernwin.BWN_*
vdui = idaapi.get_widget_vdui(widget)

Comments

# set non-repeatable comment
idc.get_cmt(ea, False)
# get repeatable comment
idc.get_cmt(ea, True)
# get func cmt
idc.get_func_cmt(ea, repeatable)
# set non-repeatable comment
idc.set_cmt(ea, comment, 0)
# set repeatable comment
idc.set_cmt(ea, comment, 1)
# set func cmt
idc.set_func_cmt(ea, comment, repeatable)

Play with segments

List segments

for s in idautils.Segments():
    start = idc.get_segm_start(s)
    end = idc.get_segm_end(s)
    name = idc.get_segm_name(s)
    data = ida_bytes.get_bytes(start, end-start)

Add segment

max_ea = idaapi.inf_get_max_ea() # get last segment end address
idaapi.add_segm(0, start_ea, end_ea, name, sclass) # sclass can be one of "CODE", "DATA", "BSS", "STACK", "XTRN", "CONST", "ABS" or "COMM"

Play with structures and types

Create a structure

name = "my_super_structure"
struct_id = idc.add_struc(0, name, 0)

Get a structure from its name

struct_id = idaapi.get_struc_id(name)
if struct_id == idaapi.BADADDR:
    print("Structure {} does not exist".format(name))

Get structure from structure id

struct = idaapi.get_struc(struct_id)

Add member to structure

# add dword
idc.add_struc_member(struct_id, member_name, member_offset, idaapi.FF_DWORD, -1, 4) 

Set type of structure member

# define type
tinfo = idaapi.tinfo_t()
[...]
member = idaapi.get_member_by_name(struct, member_name)
if idaapi.set_member_tinfo(struct, member, 0, tinfo, 0) == idaapi.SMT_OK:
    print("Member type successfully modified !")

Apply a structure on a specific EA

idaapi.apply_tinfo(ea, tinfo, idaapi.TINFO_DEFINITE)

Play with functions

Get a function

f = ida_funcs.get_func(ea)
print("%x %x" % (f.start_ea, f.end_ea))
print(ida_funcs.get_func_name(ea)) # not necessarily the start ea

for ea in Functions():
  print("%x" % ea)

Search a mnemonic in a function

f = ida_funcs.get_func(ea)
for ea in Heads(f.start_ea, f_end_ea):
  insn = idaapi.insn_t()
  length = idaapi.decode_insn(insn, ea)
  if insn.itype == ida_allins.NN_call:
    print("Call at %x" % ea)
  # also works to search for call instructions
  if ida_idp.is_call_insn(insn):
    print("Call at %x" % ea)

Get the type and the value of an operand

# Get mov instructions to memory adresses
f = ida_funcs.get_func(ea)
for ea in Heads(f.start_ea, f_end_ea):
  insn = idaapi.insn_t()
  length = idaapi.decode_insn(insn, ea)
  if insn.itype != ida_allins.NN_mov:
    continue
  if insn.ops[1].type == ida_ua.o_mem:
    print("Data is moved at addr %x" % insn.ops[1].value)

Types returned by GetOpType:

  • o_void: no operand
  • o_reg: register
  • o_mem: known address
  • o_phrase, o_displ: pointers to adresses
  • o_imm: constant value

Look for assembly code

f = ida_funcs.get_func(ea)
for ea in idautils.Heads(f.start_ea, f_end_ea):
  insn = idaapi.insn_t()
  length = idaapi.decode_insn(insn, ea)
  if insn.itype != ida_allins.NN_xor and insn.ops[0].reg == idautils.procregs.ecx and insn.ops[1].reg == idautils.procregs.ecx:
    print("Found at addr %x" % ea)

Get prototype of an imported function

# get import function prototype
import_prototype = idaapi.get_named_type(None, 'WriteFile', 0)

# deserialize import function prototype
import_tif = idaapi.tinfo_t()
import_tif.deserialize(None, import_prototype[1], import_prototype[2])

# create a pointer to the import function type
ptr_import_tif = idaapi.tinfo_t()
ptr_import_tif.create_ptr(import_tif)

GUI

Read selected code

_, start, end = idaapi.read_range_selection(None)
for ea in idautils.Heads(start, end):
    insn = idaapi.insn_t()
    length = idaapi.decode_insn(insn, ea)

Debugger

Launch the debugger

ida_dbg.add_bpt(ea, 1, ida_idd.BPT_DEFAULT)
ida_dbg.start_process("/path/to/exe", "-q 1", "/path/to")
# bp reached
ida_dbg.continue_process()
ida_dbg.exit_process()

Breakpoint types:

  • BPT_WRITE = 1
  • BPT_READ = 2
  • BPT_RDWD = 3
  • BPT_SOFT = 4
  • BPT_EXEC = 8
  • BPT_DEFAULT = BPT_SOFT|BPT_EXEC

Get a memory value

rv = ida_idd.regval_t()
ida_dbg.get_reg_val("ECX", rv)
print(hex(rv.ival))
print(hex(idautils.cpu.ecx))

Add a script in a breakpoint

  1. Add a breakpoint
  2. Right click > Edit breakpoint
  3. Click on the button at the right of Condition
  4. Change the scripting language to Python
  5. Write the code in the text zone

Call a function of the debuggee

# test check_passwd(char *passwd) -> int
passwd = ida_idd.Appcall.byref("MyFirstGuess")
res = ida_idd.Appcall.check_passwd(passwd)
if res.value == 0:
  print("Good passwd !")
else:
  print("Bad passwd...")

Other examples: http://www.hexblog.com/?p=113

@stevemk14ebr
Copy link

How about setting the type of a function? All parameters and return value

@arizvisa
Copy link

@stevemk14ebr

How about setting the type of a function? All parameters and return value

ftd.rettype = idaapi.tinfo_t(idaapi.BT_INT)
ftd.retloc.set_reg1(idaapi.ph_get_regnames().index('ax'))
ftd.cc = idaapi.CM_CC_CDECL
for index, (name, cmt) in enumerate(zip(['arg_0', 'arg_8', 'arg_10'], ['bla', 'bla', 'bla'])):
    fa = idaapi.funcarg_t()
    fa.name, fa.cmt = name, cmt
    fa.type = idaapi.tinfo_t(idaapi.BT_INT)
    fa.argloc.set_stkoff(index * ftd.rettype.get_size())
    ftd.push_back(fa)
ti = idaapi.tinfo_t()
ok = ti.create_func(ftd)
assert(ok)

@LiEnby
Copy link

LiEnby commented Mar 4, 2024

image
how do i do this programatically?

@arizvisa
Copy link

arizvisa commented Mar 4, 2024

how do i do this programatically?

Are you making dwords by right-clicking and selecting data? Picture isn't clear to me, but I'm also pretty terrible with the user-interface...

If you're trying to change the data types, you'd use the do_data_ex function, but the idc module has friendlier wrappers with names similar to idc.create_array and idc.create_dword. The idc.py file is worth a browse, and it sits in the tool's python directory.

@LiEnby
Copy link

LiEnby commented Mar 5, 2024

its a DWORD that points to another resource defined in IDA, i have to right click each one in the table and tell it its a pointer id like to do it programatically

how do i do this programatically?

Are you making dwords by right-clicking and selecting data? Picture isn't clear to me, but I'm also pretty terrible with the user-interface...

If you're trying to change the data types, you'd use the do_data_ex function, but the idc module has friendlier wrappers with names similar to idc.create_array and idc.create_dword. The idc.py file is worth a browse, and it sits in the tool's python directory.

@arizvisa
Copy link

arizvisa commented Mar 7, 2024

Once you've sized it as the data type you want, you just need to use set_refinfo(ea, OPND_ALL, reftype) to make it a reference of whichever reftype you need (REF_OFF8, REF_OFF16, REF_OFF32, REF_OFF64, etc.). You can also probably use idc.SetType with "void*" as your type information.

<advertisement>
I (sorta) maintain this plugin, ida-minsc, which has this stupid idea of using python to describe your types. Might be worth considering if you really plan on scripting.

So, using it to set a 16-bit integer for the current address would be database.set((int, 2)), 64-bit offset for a specific address database.set(ea, (type,8)), 13-element array of offsets (default word size) database.set(ea, [type, 13]). For types, you can apply one to the current address with database.type('void*') or fetch from another database.type(ea).
</advertisement>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment