#!/usr/bin/env python
#---------------------------------------------------------------------
# IDAPython - Python plugin for Interactive Disassembler
#
# Original IDC.IDC:
# Copyright (c) 1990-2010 Ilfak Guilfanov
#
# Python conversion:
# Copyright (c) 2004-2010 Gergely Erdelyi <gergely.erdelyi@d-dome.net>
#
# All rights reserved.
#
# For detailed copyright information see the file COPYING in
# the root of the distribution archive.
#---------------------------------------------------------------------
# idc.py - IDC compatibility module
#---------------------------------------------------------------------
"""
IDC compatibility module
This file contains IDA built-in function declarations and internal bit
definitions. Each byte of the program has 32-bit flags (low 8 bits keep
the byte value). These 32 bits are used in get_full_flags/get_flags functions.
This file is subject to change without any notice.
Future versions of IDA may use other definitions.
"""
# FIXME: Perhaps those should be loaded on-demand
import ida_idaapi
import ida_auto
import ida_dbg
import ida_diskio
import ida_entry
import ida_enum
import ida_expr
import ida_fixup
import ida_frame
import ida_funcs
import ida_gdl
import ida_ida
import ida_idc
import ida_bytes
import ida_idd
import ida_idp
import ida_kernwin
import ida_lines
import ida_loader
import ida_moves
import ida_nalt
import ida_name
import ida_netnode
import ida_offset
import ida_pro
import ida_search
import ida_segment
import ida_segregs
import ida_struct
import ida_typeinf
import ida_ua
import ida_xref
import _ida_idaapi
import os
import re
import struct
import time
import types
import sys
__X64__ = sys.maxsize > 0xFFFFFFFF
__EA64__ = ida_idaapi.BADADDR == 0xFFFFFFFFFFFFFFFFL
WORDMASK = 0xFFFFFFFFFFFFFFFF if __EA64__ else 0xFFFFFFFF
class DeprecatedIDCError(Exception):
"""
Exception for deprecated function calls
"""
pass
def _IDC_GetAttr(obj, attrmap, attroffs):
"""
Internal function to generically get object attributes
Do not use unless you know what you are doing
"""
if attroffs in attrmap and hasattr(obj, attrmap[attroffs][1]):
return getattr(obj, attrmap[attroffs][1])
else:
errormsg = "attribute with offset %d not found, check the offset and report the problem" % attroffs
raise KeyError, errormsg
def _IDC_SetAttr(obj, attrmap, attroffs, value):
"""
Internal function to generically set object attributes
Do not use unless you know what you are doing
"""
# check for read-only atributes
if attroffs in attrmap:
if attrmap[attroffs][0]:
raise KeyError, "attribute with offset %d is read-only" % attroffs
elif hasattr(obj, attrmap[attroffs][1]):
return setattr(obj, attrmap[attroffs][1], value)
errormsg = "attribute with offset %d not found, check the offset and report the problem" % attroffs
raise KeyError, errormsg
BADADDR = ida_idaapi.BADADDR # Not allowed address value
BADSEL = ida_idaapi.BADSEL # Not allowed selector value/number
MAXADDR = ida_ida.MAXADDR & WORDMASK
SIZE_MAX = _ida_idaapi.SIZE_MAX
#
# Flag bit definitions (for get_full_flags())
#
MS_VAL = ida_bytes.MS_VAL # Mask for byte value
FF_IVL = ida_bytes.FF_IVL # Byte has value ?
# Do flags contain byte value? (i.e. has the byte a value?)
# if not, the byte is uninitialized.
def has_value(F): return ((F & FF_IVL) != 0) # any defined value?
def byte_value(F):
"""
Get byte value from flags
Get value of byte provided that the byte is initialized.
This macro works ok only for 8-bit byte machines.
"""
return (F & MS_VAL)
def is_loaded(ea):
"""Is the byte initialized?"""
return has_value(get_full_flags(ea)) # any defined value?
MS_CLS = ida_bytes.MS_CLS # Mask for typing
FF_CODE = ida_bytes.FF_CODE # Code ?
FF_DATA = ida_bytes.FF_DATA # Data ?
FF_TAIL = ida_bytes.FF_TAIL # Tail ?
FF_UNK = ida_bytes.FF_UNK # Unknown ?
def is_code(F): return ((F & MS_CLS) == FF_CODE) # is code byte?
def is_data(F): return ((F & MS_CLS) == FF_DATA) # is data byte?
def is_tail(F): return ((F & MS_CLS) == FF_TAIL) # is tail byte?
def is_unknown(F): return ((F & MS_CLS) == FF_UNK) # is unexplored byte?
def is_head(F): return ((F & FF_DATA) != 0) # is start of code/data?
#
# Common bits
#
MS_COMM = ida_bytes.MS_COMM # Mask of common bits
FF_COMM = ida_bytes.FF_COMM # Has comment?
FF_REF = ida_bytes.FF_REF # has references?
FF_LINE = ida_bytes.FF_LINE # Has next or prev cmt lines ?
FF_NAME = ida_bytes.FF_NAME # Has user-defined name ?
FF_LABL = ida_bytes.FF_LABL # Has dummy name?
FF_FLOW = ida_bytes.FF_FLOW # Exec flow from prev instruction?
FF_ANYNAME = FF_LABL | FF_NAME
def is_flow(F): return ((F & FF_FLOW) != 0)
def isExtra(F): return ((F & FF_LINE) != 0)
def isRef(F): return ((F & FF_REF) != 0)
def hasName(F): return ((F & FF_NAME) != 0)
def hasUserName(F): return ((F & FF_ANYNAME) == FF_NAME)
MS_0TYPE = ida_bytes.MS_0TYPE # Mask for 1st arg typing
FF_0VOID = ida_bytes.FF_0VOID # Void (unknown)?
FF_0NUMH = ida_bytes.FF_0NUMH # Hexadecimal number?
FF_0NUMD = ida_bytes.FF_0NUMD # Decimal number?
FF_0CHAR = ida_bytes.FF_0CHAR # Char ('x')?
FF_0SEG = ida_bytes.FF_0SEG # Segment?
FF_0OFF = ida_bytes.FF_0OFF # Offset?
FF_0NUMB = ida_bytes.FF_0NUMB # Binary number?
FF_0NUMO = ida_bytes.FF_0NUMO # Octal number?
FF_0ENUM = ida_bytes.FF_0ENUM # Enumeration?
FF_0FOP = ida_bytes.FF_0FOP # Forced operand?
FF_0STRO = ida_bytes.FF_0STRO # Struct offset?
FF_0STK = ida_bytes.FF_0STK # Stack variable?
MS_1TYPE = ida_bytes.MS_1TYPE # Mask for 2nd arg typing
FF_1VOID = ida_bytes.FF_1VOID # Void (unknown)?
FF_1NUMH = ida_bytes.FF_1NUMH # Hexadecimal number?
FF_1NUMD = ida_bytes.FF_1NUMD # Decimal number?
FF_1CHAR = ida_bytes.FF_1CHAR # Char ('x')?
FF_1SEG = ida_bytes.FF_1SEG # Segment?
FF_1OFF = ida_bytes.FF_1OFF # Offset?
FF_1NUMB = ida_bytes.FF_1NUMB # Binary number?
FF_1NUMO = ida_bytes.FF_1NUMO # Octal number?
FF_1ENUM = ida_bytes.FF_1ENUM # Enumeration?
FF_1FOP = ida_bytes.FF_1FOP # Forced operand?
FF_1STRO = ida_bytes.FF_1STRO # Struct offset?
FF_1STK = ida_bytes.FF_1STK # Stack variable?
# The following macros answer questions like
# 'is the 1st (or 2nd) operand of instruction or data of the given type'?
# Please note that data items use only the 1st operand type (is...0)
def is_defarg0(F): return ((F & MS_0TYPE) != FF_0VOID)
def is_defarg1(F): return ((F & MS_1TYPE) != FF_1VOID)
def isDec0(F): return ((F & MS_0TYPE) == FF_0NUMD)
def isDec1(F): return ((F & MS_1TYPE) == FF_1NUMD)
def isHex0(F): return ((F & MS_0TYPE) == FF_0NUMH)
def isHex1(F): return ((F & MS_1TYPE) == FF_1NUMH)
def isOct0(F): return ((F & MS_0TYPE) == FF_0NUMO)
def isOct1(F): return ((F & MS_1TYPE) == FF_1NUMO)
def isBin0(F): return ((F & MS_0TYPE) == FF_0NUMB)
def isBin1(F): return ((F & MS_1TYPE) == FF_1NUMB)
def is_off0(F): return ((F & MS_0TYPE) == FF_0OFF)
def is_off1(F): return ((F & MS_1TYPE) == FF_1OFF)
def is_char0(F): return ((F & MS_0TYPE) == FF_0CHAR)
def is_char1(F): return ((F & MS_1TYPE) == FF_1CHAR)
def is_seg0(F): return ((F & MS_0TYPE) == FF_0SEG)
def is_seg1(F): return ((F & MS_1TYPE) == FF_1SEG)
def is_enum0(F): return ((F & MS_0TYPE) == FF_0ENUM)
def is_enum1(F): return ((F & MS_1TYPE) == FF_1ENUM)
def is_manual0(F): return ((F & MS_0TYPE) == FF_0FOP)
def is_manual1(F): return ((F & MS_1TYPE) == FF_1FOP)
def is_stroff0(F): return ((F & MS_0TYPE) == FF_0STRO)
def is_stroff1(F): return ((F & MS_1TYPE) == FF_1STRO)
def is_stkvar0(F): return ((F & MS_0TYPE) == FF_0STK)
def is_stkvar1(F): return ((F & MS_1TYPE) == FF_1STK)
#
# Bits for DATA bytes
#
DT_TYPE = ida_bytes.DT_TYPE & 0xFFFFFFFF # Mask for DATA typing
FF_BYTE = ida_bytes.FF_BYTE & 0xFFFFFFFF # byte
FF_WORD = ida_bytes.FF_WORD & 0xFFFFFFFF # word
FF_DWORD = ida_bytes.FF_DWORD & 0xFFFFFFFF # dword
FF_QWORD = ida_bytes.FF_QWORD & 0xFFFFFFFF # qword
FF_TBYTE = ida_bytes.FF_TBYTE & 0xFFFFFFFF # tbyte
FF_STRLIT = ida_bytes.FF_STRLIT & 0xFFFFFFFF # ASCII ?
FF_STRUCT = ida_bytes.FF_STRUCT & 0xFFFFFFFF # Struct ?
FF_OWORD = ida_bytes.FF_OWORD & 0xFFFFFFFF # octaword (16 bytes)
FF_FLOAT = ida_bytes.FF_FLOAT & 0xFFFFFFFF # float
FF_DOUBLE = ida_bytes.FF_DOUBLE & 0xFFFFFFFF # double
FF_PACKREAL = ida_bytes.FF_PACKREAL & 0xFFFFFFFF # packed decimal real
FF_ALIGN = ida_bytes.FF_ALIGN & 0xFFFFFFFF # alignment directive
def is_byte(F): return (is_data(F) and (F & DT_TYPE) == FF_BYTE)
def is_word(F): return (is_data(F) and (F & DT_TYPE) == FF_WORD)
def is_dword(F): return (is_data(F) and (F & DT_TYPE) == FF_DWORD)
def is_qword(F): return (is_data(F) and (F & DT_TYPE) == FF_QWORD)
def is_oword(F): return (is_data(F) and (F & DT_TYPE) == FF_OWORD)
def is_tbyte(F): return (is_data(F) and (F & DT_TYPE) == FF_TBYTE)
def is_float(F): return (is_data(F) and (F & DT_TYPE) == FF_FLOAT)
def is_double(F): return (is_data(F) and (F & DT_TYPE) == FF_DOUBLE)
def is_pack_real(F): return (is_data(F) and (F & DT_TYPE) == FF_PACKREAL)
def is_strlit(F): return (is_data(F) and (F & DT_TYPE) == FF_STRLIT)
def is_struct(F): return (is_data(F) and (F & DT_TYPE) == FF_STRUCT)
def is_align(F): return (is_data(F) and (F & DT_TYPE) == FF_ALIGN)
#
# Bits for CODE bytes
#
MS_CODE = ida_bytes.MS_CODE & 0xFFFFFFFF
FF_FUNC = ida_bytes.FF_FUNC & 0xFFFFFFFF # function start?
FF_IMMD = ida_bytes.FF_IMMD & 0xFFFFFFFF # Has Immediate value ?
FF_JUMP = ida_bytes.FF_JUMP & 0xFFFFFFFF # Has jump table
#
# Loader flags
#
NEF_SEGS = ida_loader.NEF_SEGS # Create segments
NEF_RSCS = ida_loader.NEF_RSCS # Load resources
NEF_NAME = ida_loader.NEF_NAME # Rename entries
NEF_MAN = ida_loader.NEF_MAN # Manual load
NEF_FILL = ida_loader.NEF_FILL # Fill segment gaps
NEF_IMPS = ida_loader.NEF_IMPS # Create imports section
NEF_FIRST = ida_loader.NEF_FIRST # This is the first file loaded
NEF_CODE = ida_loader.NEF_CODE # for load_binary_file:
NEF_RELOAD = ida_loader.NEF_RELOAD # reload the file at the same place:
NEF_FLAT = ida_loader.NEF_FLAT # Autocreated FLAT group (PE)
# List of built-in functions
# --------------------------
#
# The following conventions are used in this list:
# 'ea' is a linear address
# 'success' is 0 if a function failed, 1 otherwise
# 'void' means that function returns no meaningful value (always 0)
#
# All function parameter conversions are made automatically.
#
# ----------------------------------------------------------------------------
# M I S C E L L A N E O U S
# ----------------------------------------------------------------------------
def value_is_string(var): raise NotImplementedError, "this function is not needed in Python"
def value_is_long(var): raise NotImplementedError, "this function is not needed in Python"
def value_is_float(var): raise NotImplementedError, "this function is not needed in Python"
def value_is_func(var): raise NotImplementedError, "this function is not needed in Python"
def value_is_pvoid(var): raise NotImplementedError, "this function is not needed in Python"
def value_is_int64(var): raise NotImplementedError, "this function is not needed in Python"
def to_ea(seg, off):
"""
Return value of expression: ((seg<<4) + off)
"""
return (seg << 4) + off
def form(format, *args):
raise DeprecatedIDCError, "form() is deprecated. Use python string operations instead."
def substr(s, x1, x2):
raise DeprecatedIDCError, "substr() is deprecated. Use python string operations instead."
def strstr(s1, s2):
raise DeprecatedIDCError, "strstr() is deprecated. Use python string operations instead."
def strlen(s):
raise DeprecatedIDCError, "strlen() is deprecated. Use python string operations instead."
def xtol(s):
raise DeprecatedIDCError, "xtol() is deprecated. Use python long() instead."
def atoa(ea):
"""
Convert address value to a string
Return address in the form 'seg000:1234'
(the same as in line prefixes)
@param ea: address to format
"""
return ida_kernwin.ea2str(ea)
def ltoa(n, radix):
raise DeprecatedIDCError, "ltoa() is deprecated. Use python string operations instead."
def atol(s):
raise DeprecatedIDCError, "atol() is deprecated. Use python long() instead."
def rotate_left(value, count, nbits, offset):
"""
Rotate a value to the left (or right)
@param value: value to rotate
@param count: number of times to rotate. negative counter means
rotate to the right
@param nbits: number of bits to rotate
@param offset: offset of the first bit to rotate
@return: the value with the specified field rotated
all other bits are not modified
"""
assert offset >= 0, "offset must be >= 0"
assert nbits > 0, "nbits must be > 0"
mask = 2**(offset+nbits) - 2**offset
tmp = value & mask
if count > 0:
for x in xrange(count):
if (tmp >> (offset+nbits-1)) & 1:
tmp = (tmp << 1) | (1 << offset)
else:
tmp = (tmp << 1)
else:
for x in xrange(-count):
if (tmp >> offset) & 1:
tmp = (tmp >> 1) | (1 << (offset+nbits-1))
else:
tmp = (tmp >> 1)
value = (value-(value&mask)) | (tmp & mask)
return value
def rotate_dword(x, count): return rotate_left(x, count, 32, 0)
def rotate_word(x, count): return rotate_left(x, count, 16, 0)
def rotate_byte(x, count): return rotate_left(x, count, 8, 0)
# add_idc_hotkey return codes
IDCHK_OK = 0 # ok
IDCHK_ARG = -1 # bad argument(s)
IDCHK_KEY = -2 # bad hotkey name
IDCHK_MAX = -3 # too many IDC hotkeys
def add_idc_hotkey(hotkey, idcfunc):
"""
Add hotkey for IDC function
@param hotkey: hotkey name ('a', "Alt-A", etc)
@param idcfunc: IDC function name
@return: None
"""
return ida_kernwin.add_idc_hotkey(hotkey, idcfunc)
def del_idc_hotkey(hotkey):
"""
Delete IDC function hotkey
@param hotkey: hotkey code to delete
"""
return ida_kernwin.del_idc_hotkey(hotkey)
def jumpto(ea):
"""
Move cursor to the specifed linear address
@param ea: linear address
"""
return ida_kernwin.jumpto(ea)
def auto_wait():
"""
Process all entries in the autoanalysis queue
Wait for the end of autoanalysis
@note: This function will suspend execution of the calling script
till the autoanalysis queue is empty.
"""
return ida_auto.auto_wait()
def eval_idc(expr):
"""
Evaluate an IDC expression
@param expr: an expression
@return: the expression value. If there are problems, the returned value will be "IDC_FAILURE: xxx"
where xxx is the error description
@note: Python implementation evaluates IDC only, while IDC can call other registered languages
"""
rv = ida_expr.idc_value_t()
err = ida_expr.eval_idc_expr(rv, BADADDR, expr)
if err:
return "IDC_FAILURE: "+err
else:
if rv.vtype == '\x02': # long
return rv.num
elif rv.vtype == '\x07': # VT_STR
return rv.c_str()
else:
raise NotImplementedError, "eval_idc() supports only expressions returning strings or longs"
def EVAL_FAILURE(code):
"""
Check the result of eval_idc() for evaluation failures
@param code: result of eval_idc()
@return: True if there was an evaluation error
"""
return type(code) == types.StringType and code.startswith("IDC_FAILURE: ")
def save_database(idbname, flags=0):
"""
Save current database to the specified idb file
@param idbname: name of the idb file. if empty, the current idb
file will be used.
@param flags: combination of ida_loader.DBFL_... bits or 0
"""
if len(idbname) == 0:
idbname = get_idb_path()
mask = ida_loader.DBFL_KILL | ida_loader.DBFL_COMP | ida_loader.DBFL_BAK
res = ida_loader.save_database_ex(idbname, flags & mask)
return res
DBFL_BAK = ida_loader.DBFL_BAK # for compatiblity with older versions, eventually delete this
def validate_idb_names():
"""
check consistency of IDB name records
@return: number of inconsistent name records
"""
return ida_nalt.validate_idb_names()
def qexit(code):
"""
Stop execution of IDC program, close the database and exit to OS
@param code: code to exit with.
@return: -
"""
ida_pro.qexit(code)
def call_system(command):
"""
Execute an OS command.
@param command: command line to execute
@return: error code from OS
@note:
IDA will wait for the started program to finish.
In order to start the command in parallel, use OS methods.
For example, you may start another program in parallel using
"start" command.
"""
return os.system(command)
def qsleep(milliseconds):
"""
qsleep the specified number of milliseconds
This function suspends IDA for the specified amount of time
@param milliseconds: time to sleep
"""
time.sleep(float(milliseconds)/1000)
def load_and_run_plugin(name, arg):
"""
Load and run a plugin
@param name: The plugin name is a short plugin name without an extension
@param arg: integer argument
@return: 0 if could not load the plugin, 1 if ok
"""
return ida_loader.load_and_run_plugin(name, arg)
def plan_to_apply_idasgn(name):
"""
Load (plan to apply) a FLIRT signature file
@param name: signature name without path and extension
@return: 0 if could not load the signature file, !=0 otherwise
"""
return ida_funcs.plan_to_apply_idasgn(name)
#----------------------------------------------------------------------------
# C H A N G E P R O G R A M R E P R E S E N T A T I O N
#----------------------------------------------------------------------------
def delete_all_segments():
"""
Delete all segments, instructions, comments, i.e. everything
except values of bytes.
"""
ea = ida_ida.cvar.inf.min_ea
# Brute-force nuke all info from all the heads
while ea != BADADDR and ea <= ida_ida.cvar.inf.max_ea:
ida_name.del_local_name(ea)
ida_name.del_global_name(ea)
func = ida_funcs.get_func(ea)
if func:
ida_funcs.del_func_cmt(func, False)
ida_funcs.del_func_cmt(func, True)
ida_funcs.del_func(ea)
ida_bytes.del_hidden_range(ea)
seg = ida_segment.getseg(ea)
if seg:
ida_segment.del_segment_cmt(seg, False)
ida_segment.del_segment_cmt(seg, True)
ida_segment.del_segm(ea, ida_segment.SEGMOD_KEEP | ida_segment.SEGMOD_SILENT)
ea = ida_bytes.next_head(ea, ida_ida.cvar.inf.max_ea)
def create_insn(ea):
"""
Create an instruction at the specified address
@param ea: linear address
@return: 0 - can not create an instruction (no such opcode, the instruction
would overlap with existing items, etc) otherwise returns length of the
instruction in bytes
"""
return ida_ua.create_insn(ea)
def plan_and_wait(sEA, eEA, final_pass=True):
"""
Perform full analysis of the range
@param sEA: starting linear address
@param eEA: ending linear address (excluded)
@param final_pass: make the final pass over the specified range
@return: 1-ok, 0-Ctrl-Break was pressed.
"""
return ida_auto.plan_and_wait(sEA, eEA, final_pass)
def set_name(ea, name, flags=ida_name.SN_CHECK):
"""
Rename an address
@param ea: linear address
@param name: new name of address. If name == "", then delete old name
@param flags: combination of SN_... constants
@return: 1-ok, 0-failure
"""
return ida_name.set_name(ea, name, flags)
SN_CHECK = ida_name.SN_CHECK
SN_NOCHECK = ida_name.SN_NOCHECK # Don't fail if the name contains invalid characters.
# If this bit is clear, all invalid chars
# (those !is_ident_cp()) will be replaced
# by SUBSTCHAR (usually '_').
# List of valid characters is defined in ida.cfg
SN_PUBLIC = ida_name.SN_PUBLIC # if set, make name public
SN_NON_PUBLIC = ida_name.SN_NON_PUBLIC # if set, make name non-public
SN_WEAK = ida_name.SN_WEAK # if set, make name weak
SN_NON_WEAK = ida_name.SN_NON_WEAK # if set, make name non-weak
SN_AUTO = ida_name.SN_AUTO # if set, make name autogenerated
SN_NON_AUTO = ida_name.SN_NON_AUTO # if set, make name non-autogenerated
SN_NOLIST = ida_name.SN_NOLIST # if set, exclude name from the list
# if not set, then include the name into
# the list (however, if other bits are set,
# the name might be immediately excluded
# from the list)
SN_NOWARN = ida_name.SN_NOWARN # don't display a warning if failed
SN_LOCAL = ida_name.SN_LOCAL # create local name. a function should exist.
# local names can't be public or weak.
# also they are not included into the list
# of names they can't have dummy prefixes
def set_cmt(ea, comment, rptble):
"""
Set an indented regular comment of an item
@param ea: linear address
@param comment: comment string
@param rptble: is repeatable?
@return: None
"""
return ida_bytes.set_cmt(ea, comment, rptble)
def make_array(ea, nitems):
"""
Create an array.
@param ea: linear address
@param nitems: size of array in items
@note: This function will create an array of the items with the same type as
the type of the item at 'ea'. If the byte at 'ea' is undefined, then
this function will create an array of bytes.
"""
flags = ida_bytes.get_flags(ea)
if ida_bytes.is_code(flags) or ida_bytes.is_tail(flags) or ida_bytes.is_align(flags):
return False
if ida_bytes.is_unknown(flags):
flags = ida_bytes.FF_BYTE
if ida_bytes.is_struct(flags):
ti = ida_nalt.opinfo_t()
assert ida_bytes.get_opinfo(ti, ea, 0, flags), "get_opinfo() failed"
itemsize = ida_bytes.get_data_elsize(ea, flags, ti)
tid = ti.tid
else:
itemsize = ida_bytes.get_item_size(ea)
tid = BADADDR
return ida_bytes.create_data(ea, flags, itemsize*nitems, tid)
def create_strlit(ea, endea):
"""
Create a string.
This function creates a string (the string type is determined by the
value of get_inf_attr(INF_STRTYPE))
@param ea: linear address
@param endea: ending address of the string (excluded)
if endea == BADADDR, then length of string will be calculated
by the kernel
@return: 1-ok, 0-failure
@note: The type of an existing string is returned by get_str_type()
"""
return ida_bytes.create_strlit(ea, 0 if endea == BADADDR else endea - ea, get_inf_attr(INF_STRTYPE))
def create_data(ea, flags, size, tid):
"""
Create a data item at the specified address
@param ea: linear address
@param flags: FF_BYTE..FF_PACKREAL
@param size: size of item in bytes
@param tid: for FF_STRUCT the structure id
@return: 1-ok, 0-failure
"""
return ida_bytes.create_data(ea, flags, size, tid)
def create_byte(ea):
"""
Convert the current item to a byte
@param ea: linear address
@return: 1-ok, 0-failure
"""
return ida_bytes.create_byte(ea, 1)
def create_word(ea):
"""
Convert the current item to a word (2 bytes)
@param ea: linear address
@return: 1-ok, 0-failure
"""
return ida_bytes.create_word(ea, 2)
def create_dword(ea):
"""
Convert the current item to a double word (4 bytes)
@param ea: linear address
@return: 1-ok, 0-failure
"""
return ida_bytes.create_dword(ea, 4)
def create_qword(ea):
"""
Convert the current item to a quadro word (8 bytes)
@param ea: linear address
@return: 1-ok, 0-failure
"""
return ida_bytes.create_qword(ea, 8)
def create_oword(ea):
"""
Convert the current item to an octa word (16 bytes/128 bits)
@param ea: linear address
@return: 1-ok, 0-failure
"""
return ida_bytes.create_oword(ea, 16)
def create_yword(ea):
"""
Convert the current item to a ymm word (32 bytes/256 bits)
@param ea: linear address
@return: 1-ok, 0-failure
"""
return ida_bytes.create_yword(ea, 32)
def create_float(ea):
"""
Convert the current item to a floating point (4 bytes)
@param ea: linear address
@return: 1-ok, 0-failure
"""
return ida_bytes.create_float(ea, 4)
def create_double(ea):
"""
Convert the current item to a double floating point (8 bytes)
@param ea: linear address
@return: 1-ok, 0-failure
"""
return ida_bytes.create_double(ea, 8)
def create_pack_real(ea):
"""
Convert the current item to a packed real (10 or 12 bytes)
@param ea: linear address
@return: 1-ok, 0-failure
"""
return ida_bytes.create_packed_real(ea, ida_idp.ph_get_tbyte_size())
def create_tbyte(ea):
"""
Convert the current item to a tbyte (10 or 12 bytes)
@param ea: linear address
@return: 1-ok, 0-failure
"""
return ida_bytes.create_tbyte(ea, ida_idp.ph_get_tbyte_size())
def create_struct(ea, size, strname):
"""
Convert the current item to a structure instance
@param ea: linear address
@param size: structure size in bytes. -1 means that the size
will be calculated automatically
@param strname: name of a structure type
@return: 1-ok, 0-failure
"""
strid = ida_struct.get_struc_id(strname)
if size == -1:
size = ida_struct.get_struc_size(strid)
return ida_bytes.create_struct(ea, size, strid)
def create_custom_data(ea, size, dtid, fid):
"""
Convert the item at address to custom data.
@param ea: linear address.
@param size: custom data size in bytes.
@param dtid: data type ID.
@param fid: data format ID.
@return: 1-ok, 0-failure
"""
return ida_bytes.create_custdata(ea, size, dtid, fid)
def create_align(ea, count, align):
"""
Convert the current item to an alignment directive
@param ea: linear address
@param count: number of bytes to convert
@param align: 0 or 1..32
if it is 0, the correct alignment will be calculated
by the kernel
@return: 1-ok, 0-failure
"""
return ida_bytes.create_align(ea, count, align)
def define_local_var(start, end, location, name):
"""
Create a local variable
@param start: start of address range for the local variable
@param end: end of address range for the local variable
@param location: the variable location in the "[bp+xx]" form where xx is
a number. The location can also be specified as a
register name.
@param name: name of the local variable
@return: 1-ok, 0-failure
@note: For the stack variables the end address is ignored.
If there is no function at 'start' then this function.
will fail.
"""
func = ida_funcs.get_func(start)
if not func:
return 0
# Find out if location is in the [bp+xx] form
r = re.compile("\[([a-z]+)([-+][0-9a-fx]+)", re.IGNORECASE)
m = r.match(location)
if m:
# Location in the form of [bp+xx]
register = ida_idp.str2reg(m.group(1))
offset = int(m.group(2), 0)
frame = ida_frame.get_frame(func)
if register == -1 or not frame:
return 0
offset += func.frsize
member = ida_struct.get_member(frame, offset)
if member:
# Member already exists, rename it
if ida_struct.set_member_name(frame, offset, name):
return 1
else:
return 0
else:
# No member at the offset, create a new one
if ida_struct.add_struc_member(frame,
name,
offset,
ida_bytes.byteflag(),
None, 1) == 0:
return 1
else:
return 0
else:
# Location as simple register name
return ida_frame.add_regvar(func, start, end, location, name, None)
def del_items(ea, flags=0, size=1):
"""
Convert the current item to an explored item
@param ea: linear address
@param flags: combination of DELIT_* constants
@param size: size of the range to undefine
@return: None
"""
return ida_bytes.del_items(ea, flags, size)
DELIT_SIMPLE = ida_bytes.DELIT_SIMPLE # simply undefine the specified item
DELIT_EXPAND = ida_bytes.DELIT_EXPAND # propogate undefined items, for example
# if removing an instruction removes all
# references to the next instruction, then
# plan to convert to unexplored the next
# instruction too.
DELIT_DELNAMES = ida_bytes.DELIT_DELNAMES # delete any names at the specified address(es)
def set_array_params(ea, flags, litems, align):
"""
Set array representation format
@param ea: linear address
@param flags: combination of AP_... constants or 0
@param litems: number of items per line. 0 means auto
@param align: element alignment
- -1: do not align
- 0: automatic alignment
- other values: element width
@return: 1-ok, 0-failure
"""
return eval_idc("set_array_params(0x%X, 0x%X, %d, %d)"%(ea, flags, litems, align))
AP_ALLOWDUPS = 0x00000001L # use 'dup' construct
AP_SIGNED = 0x00000002L # treats numbers as signed
AP_INDEX = 0x00000004L # display array element indexes as comments
AP_ARRAY = 0x00000008L # reserved (this flag is not stored in database)
AP_IDXBASEMASK = 0x000000F0L # mask for number base of the indexes
AP_IDXDEC = 0x00000000L # display indexes in decimal
AP_IDXHEX = 0x00000010L # display indexes in hex
AP_IDXOCT = 0x00000020L # display indexes in octal
AP_IDXBIN = 0x00000030L # display indexes in binary
def op_bin(ea, n):
"""
Convert an operand of the item (instruction or data) to a binary number
@param ea: linear address
@param n: number of operand
- 0 - the first operand
- 1 - the second, third and all other operands
- -1 - all operands
@return: 1-ok, 0-failure
@note: the data items use only the type of the first operand
"""
return ida_bytes.op_bin(ea, n)
def op_oct(ea, n):
"""
Convert an operand of the item (instruction or data) to an octal number
@param ea: linear address
@param n: number of operand
- 0 - the first operand
- 1 - the second, third and all other operands
- -1 - all operands
"""
return ida_bytes.op_oct(ea, n)
def op_dec(ea, n):
"""
Convert an operand of the item (instruction or data) to a decimal number
@param ea: linear address
@param n: number of operand
- 0 - the first operand
- 1 - the second, third and all other operands
- -1 - all operands
"""
return ida_bytes.op_dec(ea, n)
def op_hex(ea, n):
"""
Convert an operand of the item (instruction or data) to a hexadecimal number
@param ea: linear address
@param n: number of operand
- 0 - the first operand
- 1 - the second, third and all other operands
- -1 - all operands
"""
return ida_bytes.op_hex(ea, n)
def op_chr(ea, n):
"""
@param ea: linear address
@param n: number of operand
- 0 - the first operand
- 1 - the second, third and all other operands
- -1 - all operands
"""
return ida_bytes.op_chr(ea, n)
def op_plain_offset(ea, n, base):
"""
Convert operand to an offset
(for the explanations of 'ea' and 'n' please see op_bin())
Example:
========
seg000:2000 dw 1234h
and there is a segment at paragraph 0x1000 and there is a data item
within the segment at 0x1234:
seg000:1234 MyString db 'Hello, world!',0
Then you need to specify a linear address of the segment base to
create a proper offset:
op_plain_offset(["seg000",0x2000],0,0x10000);
and you will have:
seg000:2000 dw offset MyString
Motorola 680x0 processor have a concept of "outer offsets".
If you want to create an outer offset, you need to combine number
of the operand with the following bit:
Please note that the outer offsets are meaningful only for
Motorola 680x0.
@param ea: linear address
@param n: number of operand
- 0 - the first operand
- 1 - the second, third and all other operands
- -1 - all operands
@param base: base of the offset as a linear address
If base == BADADDR then the current operand becomes non-offset
"""
if base == BADADDR:
return ida_bytes.clr_op_type(ea, n)
else:
return ida_offset.op_plain_offset(ea, n, base)
OPND_OUTER = ida_bytes.OPND_OUTER # outer offset base
def op_offset(ea, n, reftype, target, base, tdelta):
"""
Convert operand to a complex offset expression
This is a more powerful version of op_plain_offset() function.
It allows to explicitly specify the reference type (off8,off16, etc)
and the expression target with a possible target delta.
The complex expressions are represented by IDA in the following form:
target + tdelta - base
If the target is not present, then it will be calculated using
target = operand_value - tdelta + base
The target must be present for LOW.. and HIGH.. reference types
@param ea: linear address of the instruction/data
@param n: number of operand to convert (the same as in op_plain_offset)
@param reftype: one of REF_... constants
@param target: an explicitly specified expression target. if you don't
want to specify it, use -1. Please note that LOW... and
HIGH... reference type requre the target.
@param base: the offset base (a linear address)
@param tdelta: a displacement from the target which will be displayed
in the expression.
@return: success (boolean)
"""
return ida_offset.op_offset(ea, n, reftype, target, base, tdelta)
REF_OFF8 = ida_nalt.REF_OFF8 # 8bit full offset
REF_OFF16 = ida_nalt.REF_OFF16 # 16bit full offset
REF_OFF32 = ida_nalt.REF_OFF32 # 32bit full offset
REF_LOW8 = ida_nalt.REF_LOW8 # low 8bits of 16bit offset
REF_LOW16 = ida_nalt.REF_LOW16 # low 16bits of 32bit offset
REF_HIGH8 = ida_nalt.REF_HIGH8 # high 8bits of 16bit offset
REF_HIGH16 = ida_nalt.REF_HIGH16 # high 16bits of 32bit offset
REF_OFF64 = ida_nalt.REF_OFF64 # 64bit full offset
REFINFO_RVA = 0x10 # based reference (rva)
REFINFO_PASTEND = 0x20 # reference past an item it may point to an nonexistitng
# do not destroy alignment dirs
REFINFO_NOBASE = 0x80 # offset base is a number
# that base have be any value
# nb: base xrefs are created only if base
# points to the middle of a segment
REFINFO_SUBTRACT = 0x0100 # the reference value is subtracted from
# the base value instead of (as usual)
# being added to it
REFINFO_SIGNEDOP = 0x0200 # the operand value is sign-extended (only
# supported for REF_OFF8/16/32/64)
def op_seg(ea, n):
"""
Convert operand to a segment expression
@param ea: linear address
@param n: number of operand
- 0 - the first operand
- 1 - the second, third and all other operands
- -1 - all operands
"""
return ida_bytes.op_seg(ea, n)
def op_num(ea, n):
"""
Convert operand to a number (with default number base, radix)
@param ea: linear address
@param n: number of operand
- 0 - the first operand
- 1 - the second, third and all other operands
- -1 - all operands
"""
return ida_bytes.op_num(ea, n)
def op_flt(ea, n):
"""
Convert operand to a floating-point number
@param ea: linear address
@param n: number of operand
- 0 - the first operand
- 1 - the second, third and all other operands
- -1 - all operands
@return: 1-ok, 0-failure
"""
return ida_bytes.op_flt(ea, n)
def op_man(ea, n, opstr):
"""
Specify operand represenation manually.
@param ea: linear address
@param n: number of operand
- 0 - the first operand
- 1 - the second, third and all other operands
- -1 - all operands
@param opstr: a string represenation of the operand
@note: IDA will not check the specified operand, it will simply display
it instead of the orginal representation of the operand.
"""
return ida_bytes.set_forced_operand(ea, n, opstr)
def toggle_sign(ea, n):
"""
Change sign of the operand
@param ea: linear address
@param n: number of operand
- 0 - the first operand
- 1 - the second, third and all other operands
- -1 - all operands
"""
return ida_bytes.toggle_sign(ea, n)
def toggle_bnot(ea, n):
"""
Toggle the bitwise not operator for the operand
@param ea: linear address
@param n: number of operand
- 0 - the first operand
- 1 - the second, third and all other operands
- -1 - all operands
"""
ida_bytes.toggle_bnot(ea, n)
return True
def op_enum(ea, n, enumid, serial):
"""
Convert operand to a symbolic constant
@param ea: linear address
@param n: number of operand
- 0 - the first operand
- 1 - the second, third and all other operands
- -1 - all operands
@param enumid: id of enumeration type
@param serial: serial number of the constant in the enumeration
The serial numbers are used if there are more than
one symbolic constant with the same value in the
enumeration. In this case the first defined constant
get the serial number 0, then second 1, etc.
There could be 256 symbolic constants with the same
value in the enumeration.
"""
return ida_bytes.op_enum(ea, n, enumid, serial)
def op_stroff(ea, n, strid, delta):
"""
Convert operand to an offset in a structure
@param ea: linear address
@param n: number of operand
- 0 - the first operand
- 1 - the second, third and all other operands
- -1 - all operands
@param strid: id of a structure type
@param delta: struct offset delta. usually 0. denotes the difference
between the structure base and the pointer into the structure.
"""
path = ida_pro.tid_array(1)
path[0] = strid
return ida_bytes.op_stroff(ea, n, path.cast(), 1, delta)
def op_stkvar(ea, n):
"""
Convert operand to a stack variable
@param ea: linear address
@param n: number of operand
- 0 - the first operand
- 1 - the second, third and all other operands
- -1 - all operands
"""
return ida_bytes.op_stkvar(ea, n)
def op_offset_high16(ea, n, target):
"""
Convert operand to a high offset
High offset is the upper 16bits of an offset.
This type is used by TMS320C6 processors (and probably by other
RISC processors too)
@param ea: linear address
@param n: number of operand
- 0 - the first operand
- 1 - the second, third and all other operands
- -1 - all operands
@param target: the full value (all 32bits) of the offset
"""
return ida_offset.op_offset(ea, n, ida_nalt.REF_HIGH16, target)
def MakeVar(ea):
"""
Mark the location as "variable"
@param ea: address to mark
@return: None
@note: All that IDA does is to mark the location as "variable".
Nothing else, no additional analysis is performed.
This function may disappear in the future.
"""
ida_bytes.doVar(ea, 1)
# Every anterior/posterior line has its number.
# Anterior lines have numbers from E_PREV
# Posterior lines have numbers from E_NEXT
E_PREV = ida_lines.E_PREV
E_NEXT = ida_lines.E_NEXT
def get_extra_cmt(ea, n):
"""
Get extra comment line
@param ea: linear address
@param n: number of line (0..MAX_ITEM_LINES)
MAX_ITEM_LINES is defined in IDA.CFG
To get anterior line #n use (E_PREV + n)
To get posterior line #n use (E_NEXT + n)
@return: extra comment line string
"""
return ida_lines.get_extra_cmt(ea, n)
def update_extra_cmt(ea, n, line):
"""
Set or update extra comment line
@param ea: linear address
@param n: number of additional line (0..MAX_ITEM_LINES)
@param line: the line to display
@return: None
@note: IDA displays additional lines from number 0 up to the first unexisting
additional line. So, if you specify additional line #150 and there is no
additional line #149, your line will not be displayed. MAX_ITEM_LINES is
defined in IDA.CFG
To set anterior line #n use (E_PREV + n)
To set posterior line #n use (E_NEXT + n)
"""
ida_lines.update_extra_cmt(ea, n, line)
def del_extra_cmt(ea, n):
"""
Delete an extra comment line
@param ea: linear address
@param n: number of anterior additional line (0..MAX_ITEM_LINES)
@return: None
To delete anterior line #n use (E_PREV + n)
To delete posterior line #n use (E_NEXT + n)
"""
ida_lines.del_extra_cmt(ea, n)
def set_manual_insn(ea, insn):
"""
Specify instruction represenation manually.
@param ea: linear address
@param insn: a string represenation of the operand
@note: IDA will not check the specified instruction, it will simply
display it instead of the orginal representation.
"""
return ida_bytes.set_manual_insn(ea, insn)
def get_manual_insn(ea):
"""
Get manual representation of instruction
@param ea: linear address
@note: This function returns value set by set_manual_insn earlier.
"""
return ida_bytes.get_manual_insn(ea)
def patch_dbg_byte(ea,value):
"""
Change a byte in the debugged process memory only
@param ea: address
@param value: new value of the byte
@return: 1 if successful, 0 if not
"""
return ida_dbg.put_dbg_byte(ea, value)
def patch_byte(ea, value):
"""
Change value of a program byte
If debugger was active then the debugged process memory will be patched too
@param ea: linear address
@param value: new value of the byte
@return: 1 if the database has been modified,
0 if either the debugger is running and the process' memory
has value 'value' at address 'ea',
or the debugger is not running, and the IDB
has value 'value' at address 'ea already.
"""
return ida_bytes.patch_byte(ea, value)
def patch_word(ea, value):
"""
Change value of a program word (2 bytes)
@param ea: linear address
@param value: new value of the word
@return: 1 if the database has been modified,
0 if either the debugger is running and the process' memory
has value 'value' at address 'ea',
or the debugger is not running, and the IDB
has value 'value' at address 'ea already.
"""
return ida_bytes.patch_word(ea, value)
def patch_dword(ea, value):
"""
Change value of a double word
@param ea: linear address
@param value: new value of the double word
@return: 1 if the database has been modified,
0 if either the debugger is running and the process' memory
has value 'value' at address 'ea',
or the debugger is not running, and the IDB
has value 'value' at address 'ea already.
"""
return ida_bytes.patch_dword(ea, value)
def patch_qword(ea, value):
"""
Change value of a quad word
@param ea: linear address
@param value: new value of the quad word
@return: 1 if the database has been modified,
0 if either the debugger is running and the process' memory
has value 'value' at address 'ea',
or the debugger is not running, and the IDB
has value 'value' at address 'ea already.
"""
return ida_bytes.patch_qword(ea, value)
SR_inherit = 1 # value is inherited from the previous range
SR_user = 2 # value is specified by the user
SR_auto = 3 # value is determined by IDA
SR_autostart = 4 # as SR_auto for segment starting address
def split_sreg_range(ea, reg, value, tag=SR_user):
"""
Set value of a segment register.
@param ea: linear address
@param reg: name of a register, like "cs", "ds", "es", etc.
@param value: new value of the segment register.
@param tag: of SR_... constants
@note: IDA keeps tracks of all the points where segment register change their
values. This function allows you to specify the correct value of a segment
register if IDA is not able to find the corrent value.
"""
reg = ida_idp.str2reg(reg);
if reg >= 0:
return ida_segregs.split_sreg_range(ea, reg, value, tag)
else:
return False
def auto_mark_range(start, end, queuetype):
"""
Plan to perform an action in the future.
This function will put your request to a special autoanalysis queue.
Later IDA will retrieve the request from the queue and process
it. There are several autoanalysis queue types. IDA will process all
queries from the first queue and then switch to the second queue, etc.
"""
return ida_auto.auto_mark_range(start, end, queuetype)
def auto_unmark(start, end, queuetype):
"""
Remove range of addresses from a queue.
"""
return ida_auto.auto_unmark(start, end, queuetype)
def AutoMark(ea,qtype):
"""
Plan to analyze an address
"""
return auto_mark_range(ea,ea+1,qtype)
AU_UNK = ida_auto.AU_UNK # make unknown
AU_CODE = ida_auto.AU_CODE # convert to instruction
AU_PROC = ida_auto.AU_PROC # make function
AU_USED = ida_auto.AU_USED # reanalyze
AU_LIBF = ida_auto.AU_LIBF # apply a flirt signature (the current signature!)
AU_FINAL = ida_auto.AU_FINAL # coagulate unexplored items
#----------------------------------------------------------------------------
# P R O D U C E O U T P U T F I L E S
#----------------------------------------------------------------------------
def gen_file(filetype, path, ea1, ea2, flags):
"""
Generate an output file
@param filetype: type of output file. One of OFILE_... symbols. See below.
@param path: the output file path (will be overwritten!)
@param ea1: start address. For some file types this argument is ignored
@param ea2: end address. For some file types this argument is ignored
@param flags: bit combination of GENFLG_...
@returns: number of the generated lines.
-1 if an error occured
OFILE_EXE: 0-can't generate exe file, 1-ok
"""
f = ida_diskio.fopenWT(path)
if f:
retval = ida_loader.gen_file(filetype, f, ea1, ea2, flags)
ida_diskio.eclose(f)
return retval
else:
return -1
# output file types:
OFILE_MAP = ida_loader.OFILE_MAP
OFILE_EXE = ida_loader.OFILE_EXE
OFILE_IDC = ida_loader.OFILE_IDC
OFILE_LST = ida_loader.OFILE_LST
OFILE_ASM = ida_loader.OFILE_ASM
OFILE_DIF = ida_loader.OFILE_DIF
# output control flags:
GENFLG_MAPSEG = ida_loader.GENFLG_MAPSEG # map: generate map of segments
GENFLG_MAPNAME = ida_loader.GENFLG_MAPNAME # map: include dummy names
GENFLG_MAPDMNG = ida_loader.GENFLG_MAPDMNG # map: demangle names
GENFLG_MAPLOC = ida_loader.GENFLG_MAPLOC # map: include local names
GENFLG_IDCTYPE = ida_loader.GENFLG_IDCTYPE # idc: gen only information about types
GENFLG_ASMTYPE = ida_loader.GENFLG_ASMTYPE # asm&lst: gen information about types too
GENFLG_GENHTML = ida_loader.GENFLG_GENHTML # asm&lst: generate html (gui version only)
GEN
IDA 7.0 python / idc.py
最新推荐文章于 2025-03-31 16:52:43 发布