- IDA Pro 6.1 support

- Added AskUsingForm() with embedded forms support (check ex_askusingform.py example and formchooser.py in the SDK)
- Added idautils.DecodePreviousInstruction() / DecodePrecedingInstruction()
- Added idc.BeginTypeUpdating() / EndTypeUpdating() for fast batch type update operations
- Added more IDP callbacks
- Added UI_Hooks with a few notification events
- Added idaapi.process_ui_action() / idc.ProcessUiAction()
- Added netnode.index() to get netnode number
- Better handling of ea_t values with bitwise negation
- Execute statement hotkey (Ctrl-F3), script timeout, and other options are now configurable with Python.cfg
- bugfix: idaapi.msg() / error() and warning() so they don't accept vararg
- bugfix: processor_t.id constants were incorrect
- bugfix: get_debug_names() was broken with IDA64
- Various bugfixes
This commit is contained in:
elias.bachaalany 2011-04-18 16:07:00 +00:00
parent 63b22d00d5
commit 109158fabb
47 changed files with 7623 additions and 3153 deletions

View File

@ -1,20 +1,40 @@
Please see http://code.google.com/p/idapython/source/list for a detailed list of changes. Please see http://code.google.com/p/idapython/source/list for a detailed list of changes.
Changes from version 1.4.3 to 1.5.0
------------------------------------
- IDA Pro 6.1 support
- Added AskUsingForm() with embedded forms support (check ex_askusingform.py example and formchooser.py in the SDK)
- Added idautils.DecodePreviousInstruction() / DecodePrecedingInstruction()
- Added idc.BeginTypeUpdating() / EndTypeUpdating() for fast batch type update operations
- Added more IDP callbacks
- Added UI_Hooks with a few notification events
- Added idaapi.process_ui_action() / idc.ProcessUiAction()
- Added netnode.index() to get netnode number
- Better handling of ea_t values with bitwise negation
- Execute statement hotkey (Ctrl-F3), script timeout, and other options are now configurable with Python.cfg
- bugfix: idaapi.msg() / error() and warning() so they don't accept vararg
- bugfix: processor_t.id constants were incorrect
- bugfix: get_debug_names() was broken with IDA64
- Various bugfixes
Changes from version 1.4.2 to 1.4.3 Changes from version 1.4.2 to 1.4.3
------------------------------------ ------------------------------------
- IDA 6.0 support - IDA Pro 6.0 support
- Python CLI now prints expression evaluation result (no need to use print()) - Python CLI now prints expression evaluation result (no need to use print())
- Changed Alt-8 to Ctrl-F3 (because it conflicts with window switching key Alt+n) - Changed Alt-8 to Ctrl-F3 (because it conflicts with window switching key Alt+n)
- Added get_highlighted_identifier() - Added get_highlighted_identifier()
- Added PluginForm class to allow UI development with either PyQt4 or PySide - Added PluginForm class to allow UI development with either PyQt4 or PySide
- Added idautils.Entries() to enum entrypoints - Added idautils.Entries() to enum entrypoints
Changes from version 1.4.1 to 1.4.2 Changes from version 1.4.1 to 1.4.2
------------------------------------ ------------------------------------
- Added command completion - Added command completion
- Added necessary changes so it compiles with Python 2.7 - Added necessary changes so it compiles with Python 2.7
- Wrapped set_user_defined_prefix() - Wrapped set_user_defined_prefix()
Changes from version 1.4.0 to 1.4.1 Changes from version 1.4.0 to 1.4.1
------------------------------------ ------------------------------------
- Added cli_t - Added cli_t
@ -22,6 +42,7 @@ Changes from version 1.4.0 to 1.4.1
- Changed the copyright string to IDAPython Team - Changed the copyright string to IDAPython Team
- Some platform dependant classes are present but useable only where applicable - Some platform dependant classes are present but useable only where applicable
Changes from version 1.3.0 to 1.4.0 Changes from version 1.3.0 to 1.4.0
------------------------------------ ------------------------------------
- IDA Pro 5.7 support - IDA Pro 5.7 support
@ -35,9 +56,9 @@ Changes from version 1.3.0 to 1.4.0
- Documented all manually wrapped functions (check 'pywraps' module in the docs) - Documented all manually wrapped functions (check 'pywraps' module in the docs)
- Lots of cleanups and fixes - Lots of cleanups and fixes
Changes from version 1.2.0 to 1.3.0 Changes from version 1.2.0 to 1.3.0
------------------------------------ ------------------------------------
- IDA Pro 5.6 support - IDA Pro 5.6 support
- Added Appcall mechanism - Added Appcall mechanism
- Added procregs to idautils.py (r254) - Added procregs to idautils.py (r254)
@ -45,7 +66,6 @@ Changes from version 1.2.0 to 1.3.0
Changes from version 1.1.0 to 1.2.0 Changes from version 1.1.0 to 1.2.0
------------------------------------ ------------------------------------
- 64-bit support (largely untested) - 64-bit support (largely untested)
- IDA Pro 5.5 support - IDA Pro 5.5 support
- Long running (or inifinitely looping) scripts can now be stopped - Long running (or inifinitely looping) scripts can now be stopped
@ -58,7 +78,6 @@ Changes from version 1.1.0 to 1.2.0
Changes from version 0.9.0 to 1.0.0 Changes from version 0.9.0 to 1.0.0
----------------------------------- -----------------------------------
- Upgraded IDA Pro base version to 5.1 - Upgraded IDA Pro base version to 5.1
- Dropped Python 2.4 support - Dropped Python 2.4 support
- Mac OS X support - Mac OS X support
@ -76,7 +95,6 @@ Changes from version 0.9.0 to 1.0.0
Changes from version 0.8.0 to 0.9.0 Changes from version 0.8.0 to 0.9.0
----------------------------------- -----------------------------------
- Upgraded base version to IDA Pro 5.0 - Upgraded base version to IDA Pro 5.0
- Works with IDA Pro 5.1 - Works with IDA Pro 5.1
- Python 2.4 and 2.5 supported - Python 2.4 and 2.5 supported
@ -92,7 +110,6 @@ Changes from version 0.8.0 to 0.9.0
Changes from version 0.7.0 to 0.8.0 Changes from version 0.7.0 to 0.8.0
----------------------------------- -----------------------------------
- Added support for IDA Pro 4.9 - Added support for IDA Pro 4.9
- Dropped support for IDA Pro 4.7 - Dropped support for IDA Pro 4.7
- NOTE: Windows version is linked against Python 2.4. - NOTE: Windows version is linked against Python 2.4.

View File

@ -38,10 +38,10 @@ Mailing list for the project is hosted by Google Groups at
INSTALLATION FROM BINARIES INSTALLATION FROM BINARIES
-------------------------- --------------------------
1. Install Python 2.5 or 2.6 from http://www.python.org/ 1. Install 2.6 or 2.7 from http://www.python.org/
2. Copy the python and python64 directories to the IDA install directory 2. Copy "python" directory to %IDADIR%
3. Copy the plugins to the %IDADIR%\plugins\ 3. Copy "plugins" directory to the %IDADIR%\plugins\
4. Copy "python.cfg" to %IDADIR%\cfg
USAGE USAGE
----- -----
@ -88,3 +88,4 @@ or
The user init file is read and executed at the end of the init process. The user init file is read and executed at the end of the init process.
Please note that IDAPython can be configured with "python.cfg" file.

216
Scripts/AsmViewer.py Normal file
View File

@ -0,0 +1,216 @@
# -----------------------------------------------------------------------
# This is an example illustrating how to use customview in Python
# The sample will allow you to open an assembly file and display it in color
# (c) Hex-Rays
#
import idaapi
import idautils
import idc
import os
# ----------------------------------------------------------------------
class asm_colorizer_t(object):
def is_id(self, ch):
return ch == '_' or ch.isalpha() or '0' <= ch <= '9'
def get_identifier(self, line, x, e):
i = x
is_digit = line[i].isdigit()
while i < e:
ch = line[i]
if not self.is_id(ch):
if ch != '.' or not is_digit:
break
i += 1
return (i, line[x:i])
def get_quoted_string(self, line, x, e):
quote = line[x]
i = x + 1
while i < e:
ch = line[i]
if ch == '\\' and line[i+1] == quote:
i += 1
elif ch == quote:
i += 1 # also take the quote
break
i += 1
return (i, line[x:i])
def colorize(self, lines):
for line in lines:
line = line.rstrip()
if not line:
self.add_line()
continue
x = 0
e = len(line)
s = ""
while x < e:
ch = line[x]
# String?
if ch == '"' or ch == "'":
x, w = self.get_quoted_string(line, x, e)
s += self.as_string(w)
# Tab?
elif ch == '\t':
s += ' ' * 4
x += 1
# Comment?
elif ch == ';':
s += self.as_comment(line[x:])
# Done with this line
break
elif ch == '.' and x + 1 < e:
x, w = self.get_identifier(line, x + 1, e)
s += self.as_directive(ch + w)
# Identifiers?
elif self.is_id(ch):
x, w = self.get_identifier(line, x, e)
# Number?
if ch.isdigit():
s += self.as_num(w)
# Other identifier
else:
s += self.as_id(w)
# Output as is
else:
s += ch
x += 1
self.add_line(s)
# -----------------------------------------------------------------------
class asmview_t(idaapi.simplecustviewer_t, asm_colorizer_t):
def Create(self, fn):
# Create the customview
if not idaapi.simplecustviewer_t.Create(self, "Viewing file - %s" % os.path.basename(fn)):
return False
self.instruction_list = idautils.GetInstructionList()
self.instruction_list.extend(["ret"])
self.register_list = idautils.GetRegisterList()
self.register_list.extend(["eax", "ebx", "ecx", "edx", "edi", "esi", "ebp", "esp"])
self.fn = fn
if not self.reload_file():
return False
self.id_refresh = self.AddPopupMenu("Refresh")
self.id_close = self.AddPopupMenu("Close")
return True
def reload_file(self):
if not self.colorize_file(self.fn):
self.Close()
return False
return True
def colorize_file(self, fn):
try:
f = open(fn, "r")
lines = f.readlines()
f.close()
self.ClearLines()
self.colorize(lines)
return True
except:
return False
def add_line(self, s=None):
if not s:
s = ""
self.AddLine(s)
def as_comment(self, s):
return idaapi.COLSTR(s, idaapi.SCOLOR_RPTCMT)
def as_id(self, s):
t = s.lower()
if t in self.register_list:
return idaapi.COLSTR(s, idaapi.SCOLOR_REG)
elif t in self.instruction_list:
return idaapi.COLSTR(s, idaapi.SCOLOR_INSN)
else:
return s
def as_string(self, s):
return idaapi.COLSTR(s, idaapi.SCOLOR_STRING)
def as_num(self, s):
return idaapi.COLSTR(s, idaapi.SCOLOR_NUMBER)
def as_directive(self, s):
return idaapi.COLSTR(s, idaapi.SCOLOR_KEYWORD)
def OnPopupMenu(self, menu_id):
"""
A context (or popup) menu item was executed.
@param menu_id: ID previously registered with AddPopupMenu()
@return: Boolean
"""
if self.id_refresh == menu_id:
return self.reload_file()
elif self.id_close == menu_id:
self.Close()
return True
return False
def OnKeydown(self, vkey, shift):
"""
User pressed a key
@param vkey: Virtual key code
@param shift: Shift flag
@return Boolean. True if you handled the event
"""
# ESCAPE
if vkey == 27:
self.Close()
elif vkey == ord('H'):
lineno = self.GetLineNo()
if lineno is not None:
line, fg, bg = self.GetLine(lineno)
if line and line[0] != idaapi.SCOLOR_INV:
s = idaapi.SCOLOR_INV + line + idaapi.SCOLOR_INV
self.EditLine(lineno, s, fg, bg)
self.Refresh()
elif vkey == ord('C'):
self.ClearLines()
self.Refresh()
elif vkey == ord('S'):
print "Selection (x1, y1, x2, y2) = ", self.GetSelection()
elif vkey == ord('I'):
print "Position (line, x, y) = ", self.GetPos(mouse = 0)
else:
return False
return True
# -----------------------------------------------------------------------
class asmviewplg(idaapi.plugin_t):
flags = idaapi.PLUGIN_KEEP
comment = "ASM viewer"
help = "This is help"
wanted_name = "ASM file viewer"
wanted_hotkey = "Alt-F8"
def __init__(self):
self.view = None
def init(self):
return idaapi.PLUGIN_KEEP
def run(self, arg):
if self.view:
self.Close()
fn = idc.AskFile(0, "*.asm", "Select ASM file to view")
if not fn:
return
self.view = asmview_t()
if not self.view.Create(fn):
return
self.view.Show()
def term(self):
if self.view:
self.view.Close()
def PLUGIN_ENTRY():
return asmviewplg()

175
Scripts/CallStackWalk.py Normal file
View File

@ -0,0 +1,175 @@
"""
A script that tries to determine the call stack
Run the application with the debugger, suspend the debugger, select a thread and finally run the script.
Copyright (c) 1990-2009 Hex-Rays
ALL RIGHTS RESERVED.
v1.0 - initial version
v1.0.1 - added stack segment bitness detection, thus works with 64bit processes too
"""
import idaapi
import idc
import idautils
# -----------------------------------------------------------------------
# class to take a copy of a segment_t
class Seg():
def __init__(self, s):
self.startEA = s.startEA
self.endEA = s.endEA
self.perm = s.perm
self.bitness = s.bitness
def __cmp__(self, other):
return cmp(self.startEA, other.startEA)
# -----------------------------------------------------------------------
# each item described as:
# [ delta, [ opcode(s) ] ]
#FF10 call d,[eax]
#FF5000 call d,[eax][0]
#FF9044332211 call d,[eax][011223344]
#FF1500000100 call d,[000010000]
#FF9300000000 call d,[ebx][0]
#FF10 call d,[eax]
CallPattern = \
[
[-2, [0xFF] ],
[-3, [0xFF] ],
[-5, [0xE8] ],
[-6, [0xFF] ],
]
# -----------------------------------------------------------------------
def IsPrevInsnCall(ea):
"""
Given a return address, this function tries to check if previous instruction
is a CALL instruction
"""
global CallPattern
if ea == idaapi.BADADDR or ea < 10:
return None
for delta, opcodes in CallPattern:
# assume caller's ea
caller = ea + delta
# get the bytes
bytes = [x for x in GetDataList(caller, len(opcodes), 1)]
# do we have a match? is it a call instruction?
if bytes == opcodes and idaapi.is_call_insn(caller):
return caller
return None
# -----------------------------------------------------------------------
def CallStackWalk(nn):
class Result:
"""
Class holding the result of one call stack item
Each call stack item instance has the following attributes:
caller = ea of caller
displ = display string
sp = stack pointer
"""
def __init__(self, caller, sp):
self.caller = caller
self.sp = sp
f = idaapi.get_func(caller)
self.displ = "%08x: " % caller
if f:
self.displ += idc.GetFunctionName(caller)
t = caller - f.startEA
if t > 0: self.displ += "+" + hex(t)
else:
self.displ += hex(caller)
self.displ += " [" + hex(sp) + "]"
def __str__(self):
return self.displ
# get stack pointer
sp = cpu.Esp
seg = idaapi.getseg(sp)
if not seg:
return (False, "Could not locate stack segment!")
stack_seg = Seg(seg)
word_size = 2 ** (seg.bitness + 1)
callers = []
sp = cpu.Esp - word_size
while sp < stack_seg.endEA:
sp += word_size
ptr = idautils.GetDataList(sp, 1, word_size).next()
seg = idaapi.getseg(ptr)
# only accept executable segments
if (not seg) or ((seg.perm & idaapi.SEGPERM_EXEC) == 0):
continue
# try to find caller
caller = IsPrevInsnCall(ptr)
# we have no recognized caller, skip!
if caller is None:
continue
# do we have a debug name that is near?
if nn:
ret = nn.find(caller)
if ret:
ea = ret[0]
# function exists?
f = idaapi.get_func(ea)
if not f:
# create function
idc.MakeFunction(ea, idaapi.BADADDR)
# get the flags
f = idc.GetFlags(caller)
# no code there?
if not isCode(f):
MakeCode(caller)
callers.append(Result(caller, sp))
#
return (True, callers)
# -----------------------------------------------------------------------
# Chooser class
class CallStackWalkChoose(Choose):
def __init__(self, list, title):
Choose.__init__(self, list, title)
self.width = 250
def enter(self, n):
o = self.list[n-1]
idc.Jump(o.caller)
# -----------------------------------------------------------------------
def main():
if not idaapi.is_debugger_on():
idc.Warning("Please run the process first!")
return
if idaapi.get_process_state() != -1:
idc.Warning("Please suspend the debugger first!")
return
# only avail from IdaPython r232
if hasattr(idaapi, "NearestName"):
# get all debug names
dn = idaapi.get_debug_names(idaapi.cvar.inf.minEA, idaapi.cvar.inf.maxEA)
# initiate a nearest name search (using debug names)
nn = idaapi.NearestName(dn)
else:
nn = None
ret, callstack = CallStackWalk(nn)
if ret:
title = "Call stack walker (thread %X)" % (GetCurrentThreadId())
idaapi.close_chooser(title)
c = CallStackWalkChoose(callstack, title)
c.choose()
else:
idc.Warning("Failed to walk the stack:" + callstack)
# -----------------------------------------------------------------------
main()

101
Scripts/DbgCmd.py Normal file
View File

@ -0,0 +1,101 @@
# -----------------------------------------------------------------------
# Debugger command prompt with CustomViewers
# (c) Hex-Rays
#
import idaapi
import idc
from idaapi import simplecustviewer_t
def SendDbgCommand(cmd):
"""Sends a command to the debugger and returns the output string.
An exception will be raised if the debugger is not running or the current debugger does not export
the 'SendDbgCommand' IDC command.
"""
s = Eval('SendDbgCommand("%s");' % cmd)
if s.startswith("IDC_FAILURE"):
raise Exception, "Debugger command is available only when the debugger is active!"
return s
# -----------------------------------------------------------------------
class dbgcmd_t(simplecustviewer_t):
def Create(self):
# Form the title
title = "Debugger command window"
# Create the customview
if not simplecustviewer_t.Create(self, title):
return False
self.last_cmd = ""
self.menu_clear = self.AddPopupMenu("Clear")
self.menu_cmd = self.AddPopupMenu("New command")
self.ResetOutput()
return True
def IssueCommand(self):
s = idaapi.askstr(0, self.last_cmd, "Please enter a debugger command")
if not s:
return
# Save last command
self.last_cmd = s
# Add it using a different color
self.AddLine("debugger>" + idaapi.COLSTR(s, idaapi.SCOLOR_VOIDOP))
try:
r = SendDbgCommand(s).split("\n")
for s in r:
self.AddLine(idaapi.COLSTR(s, idaapi.SCOLOR_LIBNAME))
except:
self.AddLine(idaapi.COLSTR("Debugger is not active or does not export SendDbgCommand()", idaapi.SCOLOR_ERROR))
self.Refresh()
def ResetOutput(self):
self.ClearLines()
self.AddLine(idaapi.COLSTR("Please press INS to enter command; X to clear output", idaapi.SCOLOR_AUTOCMT))
self.Refresh()
def OnKeydown(self, vkey, shift):
# ESCAPE?
if vkey == 27:
self.Close()
# VK_INSERT
elif vkey == 45:
self.IssueCommand()
elif vkey == ord('X'):
self.ResetOutput()
else:
return False
return True
def OnPopupMenu(self, menu_id):
if menu_id == self.menu_clear:
self.ResetOutput()
elif menu_id == self.menu_cmd:
self.IssueCommand()
else:
# Unhandled
return False
return True
# -----------------------------------------------------------------------
def show_win():
x = dbgcmd_t()
if not x.Create():
print "Failed to create debugger command line!"
return None
x.Show()
return x
try:
# created already?
dbgcmd
dbgcmd.Close()
del dbgcmd
except:
pass
dbgcmd = show_win()
if not dbgcmd:
del dbgcmd

105
Scripts/DrvsDispatch.py Normal file
View File

@ -0,0 +1,105 @@
"""
A script to demonstrate how to send commands to the debugger and then parse and use the output in IDA
Copyright (c) 1990-2009 Hex-Rays
ALL RIGHTS RESERVED.
"""
import re
from idaapi import Choose
# -----------------------------------------------------------------------
def CmdDriverList():
s = Eval('WinDbgCommand("lm o");')
if "IDC_FAILURE" in s: return False
return s
# -----------------------------------------------------------------------
def CmdDrvObj(drvname, flag=2):
return Eval('WinDbgCommand("!drvobj %s %d");' % (drvname, flag))
# -----------------------------------------------------------------------
def CmdReloadForce():
s = Eval('WinDbgCommand(".reload /f");')
if "IDC_FAILURE" in s: return False
return True
# -----------------------------------------------------------------------
# class to hold dispatch entry information
class DispatchEntry:
def __init__(self, addr, name):
self.addr = addr
self.name = name
def __repr__(self):
return "%08X: %s" % (self.addr, self.name)
# -----------------------------------------------------------------------
def GetDriverDispatch():
# return a list of arrays of the form: [addr, name]
ret_list = []
# build the RE for parsing output from the "lm o" command
re_drv = re.compile('^[a-f0-9]+\s+[a-f0-9]+\s+(\S+)', re.I)
# build the RE for parsing output from the "!drvobj DRV_NAME 2" command
re_tbl = re.compile('^\[\d{2}\]\s+IRP_MJ_(\S+)\s+([0-9a-f]+)', re.I)
# force reloading of module symbols
if not CmdReloadForce():
print "Could not communicate with WinDbg, make sure the debugger is running!"
return None
# get driver list
lm_out = CmdDriverList()
if not lm_out:
return "Failed to get driver list!"
# for each line
for line in lm_out.split("\n"):
# parse
r = re_drv.match(line)
if not r: continue
# extract driver name
drvname = r.group(1).strip()
# execute "drvobj" command
tbl_out = CmdDrvObj(drvname)
if not tbl_out:
print "Failed to get driver object for", drvname
continue
# for each line
for line in tbl_out.split("\n"):
# parse
r = re_tbl.match(line)
if not r: continue
disp_addr = int(r.group(2), 16) # convert hex string to number
disp_name = "Dispatch" + r.group(1)
ret_list.append(DispatchEntry(disp_addr, drvname + "_" + disp_name))
return ret_list
# -----------------------------------------------------------------------
# Chooser class
class DispatchChoose(Choose):
def __init__(self, list, title):
Choose.__init__(self, list, title)
self.width = 250
def enter(self, n):
o = self.list[n-1]
idc.Jump(o.addr)
# -----------------------------------------------------------------------
# main
r = GetDriverDispatch()
if r:
c = DispatchChoose(r, "Dispatch table browser")
c.choose()
else:
print "Failed to retrieve dispatchers list!"

52
Scripts/ExchainDump.py Normal file
View File

@ -0,0 +1,52 @@
"""
This script shows how to send debugger commands and use the result in IDA
Copyright (c) 1990-2009 Hex-Rays
ALL RIGHTS RESERVED.
"""
import idc
import re
# class to store parsed results
class exchain:
def __init__(self, m):
self.name = m.group(1)
self.addr = int(m.group(2), 16)
def __str__(self):
return "%x: %s" % (self.addr, self.name)
# Chooser class
class MyChoose(Choose):
def __init__(self, list, title):
Choose.__init__(self, list, title)
self.width = 250
def enter(self, n):
o = self.list[n-1]
idc.Jump(o.addr)
# main
def main():
s = idc.Eval('SendDbgCommand("!exchain")')
if "IDC_FAILURE" in s:
return (False, "Cannot execute the command")
matches = re.finditer(r'[^:]+: ([^\(]+) \(([^\)]+)\)\n', s)
L = []
for x in matches:
L.append(exchain(x))
if not L:
return (False, "Nothing to display: Could parse the result!")
# Get a Choose instance
chooser = MyChoose(L, "Exchain choose")
# Run the chooser
chooser.choose()
return (True, "Success!")
ok, r = main()
if not ok:
print r

139
Scripts/FindInstructions.py Normal file
View File

@ -0,0 +1,139 @@
"""
FindInstructions.py: A script to help you find desired opcodes/instructions in a database
The script accepts opcodes and assembly statements (which will be assembled) separated by semicolon
The general syntax is:
find(asm or opcodes, x=Bool, asm_where=ea)
* Example:
find("asm_statement1;asm_statement2;de ea dc 0d e0;asm_statement3;xx yy zz;...")
* To filter-out non-executable segments pass x=True
find("jmp dword ptr [esp]", x=True)
* To specify in which context the instructions should be assembled, pass asm_where=ea:
find("jmp dword ptr [esp]", asm_where=here())
Copyright (c) 1990-2009 Hex-Rays
ALL RIGHTS RESERVED.
v1.0 - initial version
"""
import idaapi
import idautils
import idc
# -----------------------------------------------------------------------
def FindInstructions(instr, asm_where=None):
"""
Finds instructions/opcodes
@return: Returns a tuple(True, [ ea, ... ]) or a tuple(False, "error message")
"""
if not asm_where:
# get first segment
asm_where = FirstSeg()
if asm_where == idaapi.BADADDR:
return (False, "No segments defined")
# regular expression to distinguish between opcodes and instructions
re_opcode = re.compile('^[0-9a-f]{2} *', re.I)
# split lines
lines = instr.split(";")
# all the assembled buffers (for each instruction)
bufs = []
for line in lines:
if re_opcode.match(line):
# convert from hex string to a character list then join the list to form one string
buf = ''.join([chr(int(x, 16)) for x in line.split()])
else:
# assemble the instruction
ret, buf = Assemble(asm_where, line)
if not ret:
return (False, "Failed to assemble:"+line)
# add the assembled buffer
bufs.append(buf)
# join the buffer into one string
buf = ''.join(bufs)
# take total assembled instructions length
tlen = len(buf)
# convert from binary string to space separated hex string
bin_str = ' '.join(["%02X" % ord(x) for x in buf])
# find all binary strings
print "Searching for: [%s]" % bin_str
ea = MinEA()
ret = []
while True:
ea = FindBinary(ea, SEARCH_DOWN, bin_str)
if ea == idaapi.BADADDR:
break
ret.append(ea)
Message(".")
ea += tlen
if not ret:
return (False, "Could not match [%s]" % bin_str)
Message("\n")
return (True, ret)
# -----------------------------------------------------------------------
# Chooser class
class SearchResultChoose(Choose):
def __init__(self, list, title):
Choose.__init__(self, list, title)
self.width = 250
def enter(self, n):
o = self.list[n-1]
Jump(o.ea)
# -----------------------------------------------------------------------
# class to represent the results
class SearchResult:
def __init__(self, ea):
self.ea = ea
if not isCode(GetFlags(ea)):
MakeCode(ea)
t = idaapi.generate_disasm_line(ea)
if t:
line = idaapi.tag_remove(t)
else:
line = ""
func = GetFunctionName(ea)
self.display = hex(ea) + ": "
if func:
self.display += func + ": "
else:
n = SegName(ea)
if n: self.display += n + ": "
self.display += line
def __str__(self):
return self.display
# -----------------------------------------------------------------------
def find(s=None, x=False, asm_where=None):
b, ret = FindInstructions(s, asm_where)
if b:
# executable segs only?
if x:
results = []
for ea in ret:
seg = idaapi.getseg(ea)
if (not seg) or (seg.perm & idaapi.SEGPERM_EXEC) == 0:
continue
results.append(SearchResult(ea))
else:
results = [SearchResult(ea) for ea in ret]
title = "Search result for: [%s]" % s
idaapi.close_chooser(title)
c = SearchResultChoose(results, title)
c.choose()
else:
print ret
# -----------------------------------------------------------------------
print "Please use find('asm_stmt1;xx yy;...', x=Bool,asm_where=ea) to search for instructions or opcodes. Specify x=true to filter out non-executable segments"

69
Scripts/ImpRef.py Normal file
View File

@ -0,0 +1,69 @@
# -----------------------------------------------------------------------
# This is an example illustrating how to enumerate all addresses
# that refer to all imported functions in a given module
#
# (c) Hex-Rays
#
import idaapi
import idc
import idautils
import re
# -----------------------------------------------------------------------
def find_imported_funcs(dllname):
def imp_cb(ea, name, ord):
if not name:
name = ''
imports.append([ea, name, ord])
return True
imports = []
nimps = idaapi.get_import_module_qty()
for i in xrange(0, nimps):
name = idaapi.get_import_module_name(i)
if re.match(dllname, name, re.IGNORECASE) is None:
continue
idaapi.enum_import_names(i, imp_cb)
return imports
# -----------------------------------------------------------------------
def find_import_ref(dllname):
imports = find_imported_funcs(dllname)
R = dict()
for i, (ea, name,_) in enumerate(imports):
#print "%x -> %s" % (ea, name)
for xref in idautils.XrefsTo(ea):
# check if referrer is a thunk
ea = xref.frm
f = idaapi.get_func(ea)
if f and (f.flags & idaapi.FUNC_THUNK) != 0:
imports.append([f.startEA, idaapi.get_func_name(f.startEA), 0])
#print "\t%x %s: from a thunk, parent added %x" % (ea, name, f.startEA)
continue
# save results
if not R.has_key(i):
R[i] = []
R[i].append(ea)
return (imports, R)
# -----------------------------------------------------------------------
def main():
dllname = idc.AskStr('kernel32', "Enter module name")
if not dllname:
print("Cancelled")
return
imports, R = find_import_ref(dllname)
for k, v in R.items():
print(imports[k][1])
for ea in v:
print("\t%x" % ea)
# -----------------------------------------------------------------------
main()

View File

@ -0,0 +1,124 @@
# -----------------------------------------------------------------------
# This is an example illustrating how to:
# - enumerate imports
# - enumerate entrypoints
# - Use PluginForm class
# - Use PySide with PluginForm to create a Python UI
#
# (c) Hex-Rays
#
import idaapi
import idautils
from idaapi import PluginForm
from PySide import QtGui, QtCore
# --------------------------------------------------------------------------
class ImpExpForm_t(PluginForm):
def imports_names_cb(self, ea, name, ord):
self.items.append((ea, '' if not name else name, ord))
# True -> Continue enumeration
return True
def BuildImports(self):
tree = {}
nimps = idaapi.get_import_module_qty()
for i in xrange(0, nimps):
name = idaapi.get_import_module_name(i)
if not name:
continue
# Create a list for imported names
self.items = []
# Enum imported entries in this module
idaapi.enum_import_names(i, self.imports_names_cb)
if name not in tree:
tree[name] = []
tree[name].extend(self.items)
return tree
def BuildExports(self):
return list(idautils.Entries())
def PopulateTree(self):
# Clear previous items
self.tree.clear()
# Build imports
root = QtGui.QTreeWidgetItem(self.tree)
root.setText(0, "Imports")
for dll_name, imp_entries in self.BuildImports().items():
imp_dll = QtGui.QTreeWidgetItem(root)
imp_dll.setText(0, dll_name)
for imp_ea, imp_name, imp_ord in imp_entries:
item = QtGui.QTreeWidgetItem(imp_dll)
item.setText(0, "%s [0x%08x]" %(imp_name, imp_ea))
# Build exports
root = QtGui.QTreeWidgetItem(self.tree)
root.setText(0, "Exports")
for exp_i, exp_ord, exp_ea, exp_name in self.BuildExports():
item = QtGui.QTreeWidgetItem(root)
item.setText(0, "%s [#%d] [0x%08x]" % (exp_name, exp_ord, exp_ea))
def OnCreate(self, form):
"""
Called when the plugin form is created
"""
# Get parent widget
self.parent = self.FormToPySideWidget(form)
# Create tree control
self.tree = QtGui.QTreeWidget()
self.tree.setHeaderLabels(("Names",))
self.tree.setColumnWidth(0, 100)
# Create layout
layout = QtGui.QVBoxLayout()
layout.addWidget(self.tree)
self.PopulateTree()
# Populate PluginForm
self.parent.setLayout(layout)
def OnClose(self, form):
"""
Called when the plugin form is closed
"""
global ImpExpForm
del ImpExpForm
print "Closed"
def Show(self):
"""Creates the form is not created or focuses it if it was"""
return PluginForm.Show(self,
"Imports / Exports viewer",
options = PluginForm.FORM_PERSIST)
# --------------------------------------------------------------------------
def main():
global ImpExpForm
try:
ImpExpForm
except:
ImpExpForm = ImpExpForm_t()
ImpExpForm.Show()
# --------------------------------------------------------------------------
main()

85
Scripts/PteDump.py Normal file
View File

@ -0,0 +1,85 @@
import idaapi
import idc
from idaapi import Choose2
def parse_pte(str):
try:
parse_pte.re
except:
parse_pte.re = re.compile('PDE at ([0-9a-f]+)\s*PTE at ([0-9a-f]+)\ncontains ([0-9a-f]+)\s*contains ([0-9a-f]+)\npfn ([0-9]+)\s*([^ ]+)\s*pfn ([0-9a-f]+)\s*([^\r\n]+)', re.I | re.M)
parse_pte.items = ('pde', 'pte', 'pdec', 'ptec', 'pdepfn', 'pdepfns', 'ptepfn', 'ptepfns')
m = parse_pte.re.search(s)
r = {}
for i in range(0, len(parse_pte.items)):
r[parse_pte.items[i]] = m.group(i+1)
return r
class MyChoose2(Choose2):
def __init__(self, title, ea1, ea2):
Choose2.__init__(self, title, [ ["VA", 10], ["PTE attr", 30] ])
self.ea1 = ea1
self.ea2 = ea2
self.n = 0
self.icon = 5
self.items = []
self.Refresh()
self.selcount = 0
def OnGetLine(self, n):
print("getline %d" % n)
return self.items[n]
def OnGetSize(self):
n = len(self.items)
self.Refresh()
return n
def OnRefresh(self, n):
print("refresh %d" % n)
return n
def Refresh(self):
items = []
PG = 0x1000
ea1 = self.ea1
npages = (self.ea2 - ea1) / PG
for i in range(npages):
r = idc.SendDbgCommand("!pte %x" % ea1)
if not r:
return False
r = parse_pte(r)
items.append([hex(ea1), r['ptepfns']])
ea1 += PG
self.items = items
print(self.items)
return True
@staticmethod
def Execute(ea1, ea2):
c = MyChoose2("PTE Viewer [%x..%x]" % (ea1, ea2), ea1, ea2)
return (c, c.Show())
def DumpPTE(ea1, ea2):
items = []
PG = 0x1000
npages = (ea2 - ea1) / PG
for i in range(npages):
r = idc.SendDbgCommand("!pte %x" % ea1)
if not r:
return False
print r
r = parse_pte(r)
print("VA: %08X PTE: %s PDE: %s" % (ea1, r['ptepfns'], r['pdepfns']))
ea1 += PG
def DumpSegPTE(ea):
DumpPTE(idc.SegStart(ea), idc.SegEnd(ea))
DumpSegPTE(here())
#MyChoose2.Execute(0xF718F000, 0xF718F000+0x1000)

149
Scripts/SEHGraph.py Normal file
View File

@ -0,0 +1,149 @@
"""
A script that graphs all the exception handlers in a given process
It will be easy to see what thread uses what handler and what handlers are commonly used between threads
Copyright (c) 1990-2009 Hex-Rays
ALL RIGHTS RESERVED.
v1.0 - initial version
"""
import idaapi
import idautils
import idc
from idaapi import GraphViewer
# -----------------------------------------------------------------------
# Since Windbg debug module does not support get_thread_sreg_base()
# we will call the debugger engine "dg" command and parse its output
def WindbgGetRegBase(tid):
s = idc.Eval('WinDbgCommand("dg %x")' % cpu.fs)
if "IDC_FAILURE" in s:
return 0
m = re.compile("[0-9a-f]{4} ([0-9a-f]{8})")
t = m.match(s.split('\n')[-2])
if not t:
return 0
return int(t.group(1), 16)
# -----------------------------------------------------------------------
def GetFsBase(tid):
idc.SelectThread(tid)
base = idaapi.dbg_get_thread_sreg_base(tid, cpu.fs)
if base != 0:
return base
return WindbgGetRegBase(tid)
# -----------------------------------------------------------------------
# Walks the SEH chain and returns a list of handlers
def GetExceptionChain(tid):
fs_base = GetFsBase(tid)
exc_rr = Dword(fs_base)
result = []
while exc_rr != 0xffffffff:
prev = Dword(exc_rr)
handler = Dword(exc_rr + 4)
exc_rr = prev
result.append(handler)
return result
# -----------------------------------------------------------------------
class SEHGraph(GraphViewer):
def __init__(self, title, result):
GraphViewer.__init__(self, title)
self.result = result
self.names = {} # ea -> name
def OnRefresh(self):
self.Clear()
addr_id = {}
for (tid, chain) in self.result.items():
# Each node data will contain a tuple of the form: (Boolean->Is_thread, Int->Value, String->Label)
# For threads the is_thread will be true and the value will hold the thread id
# For exception handlers, is_thread=False and Value=Handler address
# Add the thread node
id_parent = self.AddNode( (True, tid, "Thread %X" % tid) )
# Add each handler
for handler in chain:
# Check if a function is created at the handler's address
f = idaapi.get_func(handler)
if not f:
# create function
idc.MakeFunction(handler, idaapi.BADADDR)
# Node label is function name or address
s = GetFunctionName(handler)
if not s:
s = "%x" % handler
# cache name
self.names[handler] = s
# Get the node id given the handler address
# We use an addr -> id dictionary so that similar addresses get similar node id
if not addr_id.has_key(handler):
id = self.AddNode( (False, handler, s) )
addr_id[handler] = id # add this ID
else:
id = addr_id[handler]
# Link handlers to each other
self.AddEdge(id_parent, id)
id_parent = id
return True
def OnGetText(self, node_id):
is_thread, value, label = self[node_id]
if is_thread:
return (label, 0xff00f0)
return label
def OnDblClick(self, node_id):
is_thread, value, label = self[node_id]
if is_thread:
idc.SelectThread(value)
self.Show()
s = "SEH chain for " + hex(value)
t = "-" * len(s)
print t
print s
print t
for handler in self.result[value]:
print "%x: %s" % (handler, self.names[handler])
print t
else:
idc.Jump(value)
return True
# -----------------------------------------------------------------------
def main():
if not idaapi.dbg_can_query():
print "The debugger must be active and suspended before using this script!"
return
# Save current thread id
tid = GetCurrentThreadId()
# Iterate through all function instructions and take only call instructions
result = {}
for tid in idautils.Threads():
result[tid] = GetExceptionChain(tid)
# Restore previously selected thread
idc.SelectThread(tid)
# Build the graph
g = SEHGraph("SEH graph", result)
g.Show()
main()

70
Scripts/VaDump.py Normal file
View File

@ -0,0 +1,70 @@
"""
This script shows how to send debugger commands and use the result in IDA
Copyright (c) 1990-2009 Hex-Rays
ALL RIGHTS RESERVED.
"""
import idc
from idaapi import Choose
import re
# class to store parsed results
class memva:
def __init__(self, m):
self.base = int(m.group(1), 16)
self.regionsize = int(m.group(2), 16)
self.state = int(m.group(3), 16)
self.statestr = m.group(4).strip()
self.protect = int(m.group(5), 16)
self.protectstr = m.group(6).strip()
if m.group(7):
self.type = int(m.group(8), 16)
self.typestr = m.group(9).strip()
else:
self.type = 0
self.typestr = ""
def __str__(self):
return "(Base %08X; RegionSize: %08X; State: %08X/%10s; protect: %08X/%10s; type: %08X/%10s)" % (
self.base, self.regionsize, self.state,
self.statestr, self.protect,
self.protectstr, self.type, self.typestr)
# Chooser class
class MemChoose(Choose):
def __init__(self, list, title):
Choose.__init__(self, list, title)
self.width = 250
def enter(self, n):
o = self.list[n-1]
idc.Jump(o.base)
# main
def main():
s = idc.Eval('SendDbgCommand("!vadump")')
if "IDC_FAILURE" in s:
return (False, "Cannot execute the command")
matches = re.finditer(r'BaseAddress:\s*?(\w+?)\n' \
+'RegionSize:\s*?(\w*?)\n' \
+'State:\s*?(\w*?)\s*?(\w*?)\n' \
+'Protect:\s*?(\w*?)\s*?(\w*?)\n' \
+'(Type:\s*?(\w*?)\s*?(\w*?)\n)*', s)
L = []
for x in matches:
L.append(memva(x))
if not L:
return (False, "Nothing to display: Could not parse the result!")
# Get a Choose instance
chooser = MemChoose(L, "Memory choose")
# Run the chooser
chooser.choose()
return (True, "Success!")
r = main()
if not r[0]:
print r[1]

68
Scripts/msdnapihelp.py Normal file
View File

@ -0,0 +1,68 @@
"""
User contributed script: MSDN API HELP plugin
This script fetches the API reference (from MSDN) of a given highlighted identifier
and returns the results in a new web browser page.
This script depends on the feedparser package: http://code.google.com/p/feedparser/
10/05/2010
- initial version
"""
import idaapi
# -----------------------------------------------------------------------
class msdnapihelp_plugin_t(idaapi.plugin_t):
flags = idaapi.PLUGIN_UNL
comment = "Online MSDN API Help"
help = "Help me"
wanted_name = "MSDN API Help"
wanted_hotkey = "F3"
def init(self):
return idaapi.PLUGIN_OK
@staticmethod
def sanitize_name(name):
t = idaapi.FUNC_IMPORT_PREFIX
if name.startswith(t):
return name[len(t):]
return name
def run(self, arg):
# Get the highlighted identifier
id = idaapi.get_highlighted_identifier()
if not id:
print "No identifier was highlighted"
return
import webbrowser
try:
import feedparser
except:
idaapi.warning('Feedparser package not installed')
return
id = self.sanitize_name(id)
print "Looking up '%s' in MSDN online" % id
d = feedparser.parse("http://social.msdn.microsoft.com/Search/Feed.aspx?locale=en-us&format=RSS&Query=%s" % id)
if len(d['entries']) > 0:
url = d['entries'][0].link
webbrowser.open_new_tab(url)
else:
print "API documentation not found for: %s" % id
def term(self):
pass
# -----------------------------------------------------------------------
def PLUGIN_ENTRY():
return msdnapihelp_plugin_t()

View File

@ -24,7 +24,7 @@ from distutils import sysconfig
VERBOSE = True VERBOSE = True
IDA_MAJOR_VERSION = 6 IDA_MAJOR_VERSION = 6
IDA_MINOR_VERSION = 0 IDA_MINOR_VERSION = 1
if 'IDA' in os.environ: if 'IDA' in os.environ:
IDA_SDK = os.environ['IDA'] IDA_SDK = os.environ['IDA']
@ -35,8 +35,8 @@ else:
# IDAPython version # IDAPython version
VERSION_MAJOR = 1 VERSION_MAJOR = 1
VERSION_MINOR = 4 VERSION_MINOR = 5
VERSION_PATCH = 3 VERSION_PATCH = 0
# Determine Python version # Determine Python version
PYTHON_MAJOR_VERSION = int(platform.python_version()[0]) PYTHON_MAJOR_VERSION = int(platform.python_version()[0])
@ -68,6 +68,7 @@ BINDIST_MANIFEST = [
"CHANGES.txt", "CHANGES.txt",
"AUTHORS.txt", "AUTHORS.txt",
"STATUS.txt", "STATUS.txt",
"python.cfg",
"docs/notes.txt", "docs/notes.txt",
"examples/chooser.py", "examples/chooser.py",
"examples/colours.py", "examples/colours.py",
@ -91,6 +92,8 @@ BINDIST_MANIFEST = [
"examples/ex_prefix_plugin.py", "examples/ex_prefix_plugin.py",
"examples/ex_pyside.py", "examples/ex_pyside.py",
"examples/ex_pyqt.py", "examples/ex_pyqt.py",
"examples/ex_askusingform.py",
"examples/ex_uihook.py",
"examples/ex_imports.py" "examples/ex_imports.py"
] ]
@ -100,6 +103,7 @@ SRCDIST_MANIFEST = [
"python.cpp", "python.cpp",
"basetsd.h", "basetsd.h",
"build.py", "build.py",
"python.cfg",
"swig/allins.i", "swig/allins.i",
"swig/area.i", "swig/area.i",
"swig/auto.i", "swig/auto.i",
@ -309,7 +313,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
platform_macros = [ "__LINUX__" ] platform_macros = [ "__LINUX__" ]
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "lib" python_libpath = sysconfig.EXEC_PREFIX + os.sep + "lib"
python_library = "-lpython%d.%d" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION) python_library = "-lpython%d.%d" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION)
ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "gcc64.lnx" or "gcc32.lnx") ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "x86_linux_gcc_64" or "x86_linux_gcc_32")
ida_lib = "" ida_lib = ""
extra_link_parameters = "" extra_link_parameters = ""
# Platform-specific settings for the Windows build # Platform-specific settings for the Windows build
@ -318,7 +322,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
platform_macros = [ "__NT__" ] platform_macros = [ "__NT__" ]
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "libs" python_libpath = sysconfig.EXEC_PREFIX + os.sep + "libs"
python_library = "python%d%d.lib" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION) python_library = "python%d%d.lib" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION)
ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "vc.w64" or "vc.w32") ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "x86_win_vc_64" or "x86_win_vc_32")
ida_lib = "ida.lib" ida_lib = "ida.lib"
SWIG_OPTIONS += " -D__NT__ " SWIG_OPTIONS += " -D__NT__ "
extra_link_parameters = "" extra_link_parameters = ""
@ -329,7 +333,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
platform_macros = [ "__MAC__" ] platform_macros = [ "__MAC__" ]
python_libpath = "." python_libpath = "."
python_library = "-framework Python" python_library = "-framework Python"
ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "gcc64.mac64" or "gcc32.mac") ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "x86_mac_gcc_64" or "x86_mac_gcc_32")
ida_lib = ea64 and "-lida64" or "-lida" ida_lib = ea64 and "-lida64" or "-lida"
extra_link_parameters = "" extra_link_parameters = ""

View File

@ -7,16 +7,17 @@
# #
from idaapi import * from idaapi import *
# Get current ea def main():
ea = get_screen_ea() # Get current ea
ea = get_screen_ea()
# Get segment class # Get segment class
seg = getseg(ea) seg = getseg(ea)
# Loop from segment start to end # Loop from segment start to end
func = get_func(seg.startEA) func = get_next_func(seg.startEA)
seg_end = seg.endEA
while func != None and func.startEA < seg.endEA: while func is not None and func.startEA < seg_end:
funcea = func.startEA funcea = func.startEA
print "Function %s at 0x%x" % (GetFunctionName(funcea), funcea) print "Function %s at 0x%x" % (GetFunctionName(funcea), funcea)
@ -27,3 +28,6 @@ while func != None and func.startEA < seg.endEA:
ref = get_next_cref_to(funcea, ref) ref = get_next_cref_to(funcea, ref)
func = get_next_func(funcea) func = get_next_func(funcea)
main()

View File

@ -7,14 +7,21 @@
# #
from idautils import * from idautils import *
# Get current ea def main():
ea = ScreenEA() # Get current ea
ea = ScreenEA()
if ea == idaapi.BADADDR:
print("Could not get get_screen_ea()")
return
# Loop from start to end in the current segment # Loop from start to end in the current segment
for funcea in Functions(SegStart(ea), SegEnd(ea)): for funcea in Functions(SegStart(ea), SegEnd(ea)):
print "Function %s at 0x%x" % (GetFunctionName(funcea), funcea) print("Function %s at 0x%x" % (GetFunctionName(funcea), funcea))
# Find all code references to funcea # Find all code references to funcea
for ref in CodeRefsTo(funcea, 1): for ref in CodeRefsTo(funcea, 1):
print " called from %s(0x%x)" % (GetFunctionName(ref), ref) print(" called from %s(0x%x)" % (GetFunctionName(ref), ref))
if __name__=='__main__':
main()

View File

@ -1,18 +1,18 @@
import idaapi import idaapi
def cb(*args): def cb(*args):
print "Callback called!" print("Callback called!")
return 1 return 1
try: try:
if ctx: ctx
idaapi.del_menu_item(ctx) idaapi.del_menu_item(ctx)
except: print("Menu removed")
pass
ctx = idaapi.add_menu_item("Search/", "X", "", 0, cb, tuple("hello world"))
if ctx is None:
print "Failed to add menu!"
del ctx del ctx
else: except:
print "Menu added successfully!" ctx = idaapi.add_menu_item("Search/", "X", "", 0, cb, tuple("hello world"))
if ctx is None:
print("Failed to add menu!")
del ctx
else:
print("Menu added successfully. Run the script again to delete the menu")

221
examples/ex_askusingform.py Normal file
View File

@ -0,0 +1,221 @@
# -----------------------------------------------------------------------
# This is an example illustrating how to use the Form class
# (c) Hex-Rays
#
from idaapi import Form
#<pycode(ex_askusingform)>
# --------------------------------------------------------------------------
class TestEmbeddedChooserClass(Choose2):
"""
A simple chooser to be used as an embedded chooser
"""
def __init__(self, title, nb = 5, flags=0):
Choose2.__init__(self,
title,
[ ["Address", 10], ["Name", 30] ],
embedded=True, width=30, height=20, flags=flags)
self.n = 0
self.items = [ self.make_item() for x in xrange(0, nb+1) ]
self.icon = 5
self.selcount = 0
def make_item(self):
r = [str(self.n), "func_%04d" % self.n]
self.n += 1
return r
def OnClose(self):
pass
def OnGetLine(self, n):
print("getline %d" % n)
return self.items[n]
def OnGetSize(self):
n = len(self.items)
print("getsize -> %d" % n)
return n
# --------------------------------------------------------------------------
class MyForm(Form):
def __init__(self):
self.invert = False
self.EChooser = TestEmbeddedChooserClass("E1", flags=Choose2.CH_MULTI)
Form.__init__(self, r"""STARTITEM {id:rNormal}
BUTTON YES* Yeah
BUTTON NO Nope
BUTTON CANCEL Nevermind
Form Test
{FormChangeCb}
This is a string: +{cStr1}+
This is an address: +{cAddr1}+
Escape\{control}
This is a string: '{cStr2}'
This is a number: {cVal1}
<#Hint1#Enter name:{iStr1}>
<#Hint2#Select color:{iColor1}>
Browse test
<#Select a file to open#Browse to open:{iFileOpen}>
<#Select a file to save#Browse to save:{iFileSave}>
<#Select dir#Browse for dir:{iDir}>
Type
<#Select type#Write a type:{iType}>
Numbers
<##Enter a selector value:{iSegment}>
<##Enter a raw hex:{iRawHex}>
<##Enter a character:{iChar}>
<##Enter an address:{iAddr}>
Button test
<##Button1:{iButton1}> <##Button2:{iButton2}>
Check boxes:
<Error output:{rError}>
<Normal output:{rNormal}>
<Warnings:{rWarnings}>{cGroup1}>
Radio boxes:
<Green:{rGreen}>
<Red:{rRed}>
<Blue:{rBlue}>{cGroup2}>
<Embedded chooser:{cEChooser}>
The end!
""", {
'cStr1': Form.StringLabel("Hello"),
'cStr2': Form.StringLabel("StringTest"),
'cAddr1': Form.NumericLabel(0x401000, Form.FT_ADDR),
'cVal1' : Form.NumericLabel(99, Form.FT_HEX),
'iStr1': Form.StringInput(),
'iColor1': Form.ColorInput(),
'iFileOpen': Form.FileInput(open=True),
'iFileSave': Form.FileInput(save=True),
'iDir': Form.DirInput(),
'iType': Form.StringInput(tp=Form.FT_TYPE),
'iSegment': Form.NumericInput(tp=Form.FT_SEG),
'iRawHex': Form.NumericInput(tp=Form.FT_RAWHEX),
'iAddr': Form.NumericInput(tp=Form.FT_ADDR),
'iChar': Form.NumericInput(tp=Form.FT_CHAR),
'iButton1': Form.ButtonInput(self.OnButton1),
'iButton2': Form.ButtonInput(self.OnButton2),
'cGroup1': Form.ChkGroupControl(("rNormal", "rError", "rWarnings")),
'cGroup2': Form.RadGroupControl(("rRed", "rGreen", "rBlue")),
'FormChangeCb': Form.FormChangeCb(self.OnFormChange),
'cEChooser' : Form.EmbeddedChooserControl(self.EChooser)
})
def OnButton1(self, code=0):
print("Button1 pressed")
def OnButton2(self, code=0):
print("Button2 pressed")
def OnFormChange(self, fid):
if fid == self.iButton1.id:
print("Button1 fchg;inv=%s" % self.invert)
self.SetFocusedField(self.rNormal.id)
self.EnableField(self.rError.id, self.invert)
self.invert = not self.invert
elif fid == self.iButton2.id:
g1 = self.GetControlValue(self.cGroup1)
g2 = self.GetControlValue(self.cGroup2)
d = self.GetControlValue(self.iDir)
f = self.GetControlValue(self.iFileOpen)
print("cGroup2:%x;Dir=%s;fopen=%s;cGroup1:%x" % (g1, d, f, g2))
elif fid == self.cEChooser.id:
l = self.GetControlValue(self.cEChooser)
print("Chooser: %s" % l)
else:
print(">>fid:%d" % fid)
return 1
# --------------------------------------------------------------------------
def stdalone_main():
f = MyForm()
f, args = f.Compile()
print args[0]
print args[1:]
f.rNormal.checked = True
f.rWarnings.checked = True
print hex(f.cGroup1.value)
f.rGreen.selected = True
print f.cGroup2.value
print "Title: '%s'" % f.title
f.Free()
# --------------------------------------------------------------------------
def ida_main():
# Create form
global f
f = MyForm()
# Compile (in order to populate the controls)
f.Compile()
f.iColor1.value = 0x5bffff
f.iDir.value = os.getcwd()
f.rNormal.checked = True
f.rWarnings.checked = True
f.rGreen.selected = True
f.iStr1.value = "Hello"
# Execute the form
ok = f.Execute()
print("r=%d" % ok)
if ok == 1:
print("f.str1=%s" % f.iStr1.value)
print("f.color1=%x" % f.iColor1.value)
print("f.openfile=%s" % f.iFileOpen.value)
print("f.savefile=%s" % f.iFileSave.value)
print("f.dir=%s" % f.iDir.value)
print("f.type=%s" % f.iType.value)
print("f.seg=%s" % f.iSegment.value)
print("f.rawhex=%x" % f.iRawHex.value)
print("f.char=%x" % f.iChar.value)
print("f.addr=%x" % f.iAddr.value)
print("f.cGroup1=%x" % f.cGroup1.value)
print("f.cGroup2=%x" % f.cGroup2.value)
sel = f.EChooser.GetEmbSelection()
if sel is None:
print("No selection")
else:
print("Selection: %s" % sel)
# Dispose the form
f.Free()
# --------------------------------------------------------------------------
def ida_main_legacy():
# Here we simply show how to use the old style form format using Python
# Sample form from kernwin.hpp
s = """Sample dialog box
This is sample dialog box for %A
using address %$
<~E~nter value:N:32:16::>
"""
# Use either StringArgument or NumericArgument to pass values to the function
num = Form.NumericArgument('N', value=123)
ok = idaapi.AskUsingForm(s,
Form.StringArgument("PyAskUsingForm").arg,
Form.NumericArgument('$', 0x401000).arg,
num.arg)
if ok == 1:
print("You entered: %x" % num.value)
#</pycode(ex_askusingform)>
# --------------------------------------------------------------------------
ida_main()

View File

@ -10,38 +10,39 @@ class MyChoose2(Choose2):
self.icon = 5 self.icon = 5
self.selcount = 0 self.selcount = 0
self.popup_names = ["Inzert", "Del leet", "Ehdeet", "Ree frech"] self.popup_names = ["Inzert", "Del leet", "Ehdeet", "Ree frech"]
print "created", str(self) print("created %s" % str(self))
def OnClose(self): def OnClose(self):
print "closed", str(self) print "closed", str(self)
def OnEditLine(self, n): def OnEditLine(self, n):
self.items[n][1] = self.items[n][1] + "*" self.items[n][1] = self.items[n][1] + "*"
print "editing", str(n) print("editing %d" % n)
def OnInsertLine(self): def OnInsertLine(self):
self.items.append(self.make_item()) self.items.append(self.make_item())
print "insert line" print("insert line")
def OnSelectLine(self, n): def OnSelectLine(self, n):
self.selcount += 1 self.selcount += 1
Warning("[%02d] selectline '%s'" % (self.selcount, n)) Warning("[%02d] selectline '%s'" % (self.selcount, n))
def OnGetLine(self, n): def OnGetLine(self, n):
print "getline", str(n) print("getline %d" % n)
return self.items[n] return self.items[n]
def OnGetSize(self): def OnGetSize(self):
print "getsize" n = len(self.items)
return len(self.items) print("getsize -> %d" % n)
return n
def OnDeleteLine(self, n): def OnDeleteLine(self, n):
print "del ",str(n) print("del %d " % n)
del self.items[n] del self.items[n]
return n return n
def OnRefresh(self, n): def OnRefresh(self, n):
print "refresh", n print("refresh %d" % n)
return n return n
def OnCommand(self, n, cmd_id): def OnCommand(self, n, cmd_id):
@ -73,7 +74,7 @@ class MyChoose2(Choose2):
return r return r
def OnGetLineAttr(self, n): def OnGetLineAttr(self, n):
print "getlineattr", n print("getlineattr %d" % n)
if n == 1: if n == 1:
return [0xFF0000, 0] return [0xFF0000, 0]
@ -81,4 +82,3 @@ for i in xrange(1, 5+1):
c = MyChoose2("choose2 - sample %d" % i, i*2) c = MyChoose2("choose2 - sample %d" % i, i*2)
r = c.show() r = c.show()
print r print r

View File

@ -1,6 +1,9 @@
import idautils import idautils
s = Strings(False) s = idautils.Strings(False)
s.setup(strtypes=Strings.STR_UNICODE | Strings.STR_C) s.setup(strtypes=Strings.STR_UNICODE | Strings.STR_C)
for i in s: for i, v in enumerate(s):
print "%x: len=%d type=%d -> '%s'" % (i.ea, i.length, i.type, str(i)) if v is None:
print("Failed to retrieve string index %d" % i)
else:
print("%x: len=%d type=%d index=%d-> '%s'" % (v.ea, v.length, v.type, i, str(v)))

42
examples/ex_uihook.py Normal file
View File

@ -0,0 +1,42 @@
#---------------------------------------------------------------------
# UI hook example
#
# (c) Hex-Rays
#
# Maintained By: IDAPython Team
#
#---------------------------------------------------------------------
import idaapi
class MyUiHook(idaapi.UI_Hooks):
def __init__(self):
idaapi.UI_Hooks.__init__(self)
self.cmdname = "<no command>"
def preprocess(self, name):
print("IDA preprocessing command: %s" % name)
self.cmdname = name
return 0
def postprocess(self):
print("IDA finished processing command: %s" % self.cmdname)
return 0
#---------------------------------------------------------------------
# Remove an existing hook on second run
try:
ui_hook_stat = "un"
print("UI hook: checking for hook...")
uihook
print("UI hook: unhooking....")
uihook.unhook()
del uihook
except:
print("UI hook: not installed, installing now....")
ui_hook_stat = ""
uihook = MyUiHook()
uihook.hook()
print("UI hook %sinstalled. Run the script again to %sinstall" % (ui_hook_stat, ui_hook_stat))

View File

@ -49,10 +49,10 @@
#define IDAPYTHON_DISABLE_EXTLANG 4 #define IDAPYTHON_DISABLE_EXTLANG 4
#define PYTHON_DIR_NAME "python" #define PYTHON_DIR_NAME "python"
#define S_IDAPYTHON "IDAPython" #define S_IDAPYTHON "IDAPython"
#define S_INIT_PY "init.py"
static const char S_IDC_ARGS_VARNAME[] = "ARGV"; static const char S_IDC_ARGS_VARNAME[] = "ARGV";
static const char S_MAIN[] = "__main__"; static const char S_MAIN[] = "__main__";
static const char S_IDC_RUNPYTHON_STATEMENT[] = "RunPythonStatement"; static const char S_IDC_RUNPYTHON_STATEMENT[] = "RunPythonStatement";
static const char S_HOTKEY_RUNSTATEMENT[] = "Ctrl-F3";
static const char S_IDAPYTHON_DATA_NODE[] = "IDAPython_Data"; static const char S_IDAPYTHON_DATA_NODE[] = "IDAPython_Data";
#ifdef PLUGINFIX #ifdef PLUGINFIX
@ -79,6 +79,7 @@ static bool g_menu_installed = false;
static int g_run_when = -1; static int g_run_when = -1;
static char g_run_script[QMAXPATH]; static char g_run_script[QMAXPATH];
static char g_idapython_dir[QMAXPATH]; static char g_idapython_dir[QMAXPATH];
static char g_runstmt_hotkey[30] = "Ctrl-F3";
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// Prototypes and forward declarations // Prototypes and forward declarations
@ -124,6 +125,9 @@ static bool box_displayed; // has the wait box been displayed?
static time_t start_time; // the start time of the execution static time_t start_time; // the start time of the execution
static int script_timeout = 2; static int script_timeout = 2;
static bool g_ui_ready = false; static bool g_ui_ready = false;
static bool g_alert_auto_scripts = true;
static bool g_remove_cwd_sys_path = false;
void end_execution(); void end_execution();
void begin_execution(); void begin_execution();
@ -133,14 +137,15 @@ static int break_check(PyObject *obj, _frame *frame, int what, PyObject *arg)
{ {
if ( wasBreak() ) if ( wasBreak() )
{ {
/* User pressed Cancel in the waitbox; send KeyboardInterrupt exception */ // User pressed Cancel in the waitbox; send KeyboardInterrupt exception
PyErr_SetInterrupt(); PyErr_SetInterrupt();
} }
else if ( !box_displayed && ++ninsns > 10 ) else if ( !box_displayed && ++ninsns > 10 )
{ {
/* We check the timer once every 10 calls */ // We check the timer once every 10 calls
ninsns = 0; ninsns = 0;
if ( script_timeout != 0 && (time(NULL) - start_time > script_timeout) ) /* Timeout elapsed? */ // Timeout disabled or elapsed?
if ( script_timeout != 0 && (time(NULL) - start_time > script_timeout) )
{ {
box_displayed = true; box_displayed = true;
show_wait_box("Running Python script"); show_wait_box("Running Python script");
@ -323,13 +328,13 @@ static void handle_python_error(char *errbuf, size_t errbufsize)
static PyObject *GetMainGlobals() static PyObject *GetMainGlobals()
{ {
PyObject *module = PyImport_AddModule(S_MAIN); PyObject *module = PyImport_AddModule(S_MAIN);
if ( module == NULL ) return module == NULL ? NULL : PyModule_GetDict(module);
return NULL;
return PyModule_GetDict(module);
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
static void PythonEvalOrExec(const char *str, const char *filename = "<string>") static void PythonEvalOrExec(
const char *str,
const char *filename = "<string>")
{ {
// Compile as an expression // Compile as an expression
PyCompilerFlags cf = {0}; PyCompilerFlags cf = {0};
@ -345,11 +350,12 @@ static void PythonEvalOrExec(const char *str, const char *filename = "<string>")
} }
PyObject *py_globals = GetMainGlobals(); PyObject *py_globals = GetMainGlobals();
PYW_GIL_ENSURE;
PyObject *py_result = PyEval_EvalCode( PyObject *py_result = PyEval_EvalCode(
(PyCodeObject *) py_code, (PyCodeObject *) py_code,
py_globals, py_globals,
py_globals); py_globals);
PYW_GIL_RELEASE;
Py_DECREF(py_code); Py_DECREF(py_code);
if ( py_result == NULL || PyErr_Occurred() ) if ( py_result == NULL || PyErr_Occurred() )
@ -379,7 +385,13 @@ static error_t idaapi idc_runpythonstatement(idc_value_t *argv, idc_value_t *res
PyErr_Clear(); PyErr_Clear();
begin_execution(); begin_execution();
PyObject *result = PyRun_String(argv[0].c_str(), Py_file_input, globals, globals ); PYW_GIL_ENSURE;
PyObject *result = PyRun_String(
argv[0].c_str(),
Py_file_input,
globals,
globals);
PYW_GIL_RELEASE;
Py_XDECREF(result); Py_XDECREF(result);
end_execution(); end_execution();
@ -401,6 +413,45 @@ static error_t idaapi idc_runpythonstatement(idc_value_t *argv, idc_value_t *res
return eOk; return eOk;
} }
//--------------------------------------------------------------------------
const char *idaapi set_python_options(
const char *keyword,
int value_type,
const void *value)
{
do
{
if ( value_type == IDPOPT_STR )
{
if ( qstrcmp(keyword, "EXEC_STATEMENT_HOTKEY" ) == 0 )
{
qstrncpy(g_runstmt_hotkey, (const char *)value, sizeof(g_runstmt_hotkey));
break;
}
}
else if ( value_type == IDPOPT_NUM )
{
if ( qstrcmp(keyword, "SCRIPT_TIMEOUT") == 0 )
{
script_timeout = int(*(uval_t *)value);
break;
}
else if ( qstrcmp(keyword, "ALERT_AUTO_SCRIPTS") == 0 )
{
g_alert_auto_scripts = *(uval_t *)value != 0;
break;
}
else if ( qstrcmp(keyword, "REMOVE_CWD_SYS_PATH") == 0 )
{
g_remove_cwd_sys_path = *(uval_t *)value != 0;
break;
}
}
return IDPOPT_BADKEY;
} while (false);
return IDPOPT_OK;
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// Check for the presence of a file in IDADIR/python and complain on error // Check for the presence of a file in IDADIR/python and complain on error
bool CheckScriptFiles() bool CheckScriptFiles()
@ -408,7 +459,7 @@ bool CheckScriptFiles()
static const char *const script_files[] = static const char *const script_files[] =
{ {
S_IDC_MODNAME ".py", S_IDC_MODNAME ".py",
"init.py", S_INIT_PY,
"idaapi.py", "idaapi.py",
"idautils.py" "idautils.py"
}; };
@ -439,9 +490,19 @@ static int PyRunFile(const char *FileName)
return 0; return 0;
} }
PyErr_Clear(); PyErr_Clear();
PyObject *result = PyRun_File(PyFile_AsFile(PyFileObject), FileName, Py_file_input, globals, globals);
PYW_GIL_ENSURE;
PyObject *result = PyRun_File(
PyFile_AsFile(PyFileObject),
FileName,
Py_file_input,
globals,
globals);
PYW_GIL_RELEASE;
Py_XDECREF(PyFileObject); Py_XDECREF(PyFileObject);
Py_XDECREF(result); Py_XDECREF(result);
return result != NULL && !PyErr_Occurred(); return result != NULL && !PyErr_Occurred();
} }
@ -461,7 +522,7 @@ void IDAPython_RunStatement(void)
if ( history.getblob(statement, &statement_size, 0, 'A') == NULL ) if ( history.getblob(statement, &statement_size, 0, 'A') == NULL )
statement[0] = '\0'; statement[0] = '\0';
if ( asktext(sizeof(statement), statement, statement, "Enter Python expressions") != NULL ) if ( asktext(sizeof(statement), statement, statement, "ACCEPT TABS\nEnter Python expressions") != NULL )
{ {
begin_execution(); begin_execution();
PyRun_SimpleString(statement); PyRun_SimpleString(statement);
@ -489,7 +550,13 @@ static bool IDAPython_ExecFile(const char *FileName, char *errbuf, size_t errbuf
strrpl(script, '\\', '//'); strrpl(script, '\\', '//');
PyObject *py_script = PyString_FromString(script); PyObject *py_script = PyString_FromString(script);
PyObject *py_ret = PyObject_CallFunctionObjArgs(py_execscript, py_script, GetMainGlobals(), NULL); PYW_GIL_ENSURE;
PyObject *py_ret = PyObject_CallFunctionObjArgs(
py_execscript,
py_script,
GetMainGlobals(),
NULL);
PYW_GIL_RELEASE;
Py_DECREF(py_script); Py_DECREF(py_script);
Py_DECREF(py_execscript); Py_DECREF(py_execscript);
@ -516,7 +583,7 @@ static bool IDAPython_ExecFile(const char *FileName, char *errbuf, size_t errbuf
} }
// Cannot be otherwise! // Cannot be otherwise!
else else
INTERR(); INTERR(30154);
Py_XDECREF(py_ret); Py_XDECREF(py_ret);
return ok; return ok;
@ -527,10 +594,12 @@ static bool IDAPython_ExecFile(const char *FileName, char *errbuf, size_t errbuf
static bool RunScript(const char *script) static bool RunScript(const char *script)
{ {
begin_execution(); begin_execution();
char errbuf[MAXSTR]; char errbuf[MAXSTR];
bool ok = IDAPython_ExecFile(script, errbuf, sizeof(errbuf)); bool ok = IDAPython_ExecFile(script, errbuf, sizeof(errbuf));
if ( !ok ) if ( !ok )
warning("IDAPython: error executing '%s':\n%s", script, errbuf); warning("IDAPython: error executing '%s':\n%s", script, errbuf);
end_execution(); end_execution();
return ok; return ok;
} }
@ -612,7 +681,6 @@ bool idaapi IDAPython_extlang_compile(
size_t errbufsize) size_t errbufsize)
{ {
PyObject *globals = GetMainGlobals(); PyObject *globals = GetMainGlobals();
QASSERT(globals != NULL);
PyCodeObject *code = (PyCodeObject *)Py_CompileString(expr, "<string>", Py_eval_input); PyCodeObject *code = (PyCodeObject *)Py_CompileString(expr, "<string>", Py_eval_input);
if ( code == NULL ) if ( code == NULL )
@ -621,11 +689,11 @@ bool idaapi IDAPython_extlang_compile(
return false; return false;
} }
// set the desired function name // Set the desired function name
Py_XDECREF(code->co_name); Py_XDECREF(code->co_name);
code->co_name = PyString_FromString(name); code->co_name = PyString_FromString(name);
// create a function out of code // Create a function out of code
PyObject *func = PyFunction_New((PyObject *)code, globals); PyObject *func = PyFunction_New((PyObject *)code, globals);
if ( func == NULL ) if ( func == NULL )
@ -672,16 +740,18 @@ bool idaapi IDAPython_extlang_run(
if ( imported_module ) if ( imported_module )
{ {
PYW_GIL_ENSURE;
module = PyImport_ImportModule(modname); module = PyImport_ImportModule(modname);
PYW_GIL_RELEASE;
} }
else else
{ {
module = PyImport_AddModule(S_MAIN); module = PyImport_AddModule(S_MAIN);
QASSERT(module != NULL); QASSERT(30156, module != NULL);
} }
PyObject *globals = PyModule_GetDict(module); PyObject *globals = PyModule_GetDict(module);
QASSERT(globals != NULL); QASSERT(30157, globals != NULL);
PyObject *func = PyDict_GetItemString(globals, funcname); PyObject *func = PyDict_GetItemString(globals, funcname);
if ( func == NULL ) if ( func == NULL )
@ -692,12 +762,13 @@ bool idaapi IDAPython_extlang_run(
} }
PyCodeObject *code = (PyCodeObject *) PyFunction_GetCode(func); PyCodeObject *code = (PyCodeObject *) PyFunction_GetCode(func);
PYW_GIL_ENSURE;
PyObject *pres = PyEval_EvalCodeEx( PyObject *pres = PyEval_EvalCodeEx(
code, code,
globals, NULL, globals, NULL,
&pargs[0], nargs, &pargs[0], nargs,
NULL, 0, NULL, 0, NULL); NULL, 0, NULL, 0, NULL);
PYW_GIL_RELEASE;
ok = return_python_result(result, pres, errbuf, errbufsize); ok = return_python_result(result, pres, errbuf, errbufsize);
} while ( false ); } while ( false );
@ -766,7 +837,9 @@ bool idaapi IDAPython_extlang_create_object(
ok = false; ok = false;
// Call the constructor // Call the constructor
PYW_GIL_ENSURE;
PyObject *py_res = PyObject_CallObject(py_cls, pargs.empty() ? NULL : pargs[0]); PyObject *py_res = PyObject_CallObject(py_cls, pargs.empty() ? NULL : pargs[0]);
PYW_GIL_RELEASE;
ok = return_python_result(result, py_res, errbuf, errbufsize); ok = return_python_result(result, py_res, errbuf, errbufsize);
} while ( false ); } while ( false );
@ -944,7 +1017,9 @@ bool idaapi IDAPython_extlang_calcexpr(
return false; return false;
begin_execution(); begin_execution();
PYW_GIL_ENSURE;
PyObject *result = PyRun_String(expr, Py_eval_input, globals, globals); PyObject *result = PyRun_String(expr, Py_eval_input, globals, globals);
PYW_GIL_RELEASE;
end_execution(); end_execution();
return return_python_result(rv, result, errbuf, errbufsize); return return_python_result(rv, result, errbuf, errbufsize);
@ -998,7 +1073,9 @@ bool idaapi IDAPython_extlang_call_method(
if ( !ok ) if ( !ok )
break; break;
PYW_GIL_ENSURE;
PyObject *py_res = PyObject_CallObject(py_method, pargs.empty() ? NULL : pargs[0]); PyObject *py_res = PyObject_CallObject(py_method, pargs.empty() ? NULL : pargs[0]);
PYW_GIL_RELEASE;
ok = return_python_result(result, py_res, errbuf, errbufsize); ok = return_python_result(result, py_res, errbuf, errbufsize);
} while ( false ); } while ( false );
@ -1030,6 +1107,7 @@ extlang_t extlang_python =
IDAPython_extlang_call_method IDAPython_extlang_call_method
}; };
//-------------------------------------------------------------------------
void enable_extlang_python(bool enable) void enable_extlang_python(bool enable)
{ {
if ( enable ) if ( enable )
@ -1042,7 +1120,7 @@ void enable_extlang_python(bool enable)
// Execute a line in the Python CLI // Execute a line in the Python CLI
bool idaapi IDAPython_cli_execute_line(const char *line) bool idaapi IDAPython_cli_execute_line(const char *line)
{ {
// do not process empty lines // Do not process empty lines
if ( line[0] == '\0' ) if ( line[0] == '\0' )
return true; return true;
@ -1052,11 +1130,11 @@ bool idaapi IDAPython_cli_execute_line(const char *line)
else else
last_line += 1; last_line += 1;
// skip empty lines // Skip empty lines
if ( last_line[0] != '\0' ) if ( last_line[0] != '\0' )
{ {
// line ends with ":" or begins with a space character? // Line ends with ":" or begins with a space character?
bool more = last_line[qstrlen(last_line)-1] == ':' || isspace(last_line[0]); bool more = last_line[qstrlen(last_line)-1] == ':' || qisspace(last_line[0]);
if ( more ) if ( more )
return false; return false;
} }
@ -1080,7 +1158,9 @@ bool idaapi IDAPYthon_cli_complete_line(
if ( py_complete == NULL ) if ( py_complete == NULL )
return false; return false;
PYW_GIL_ENSURE;
PyObject *py_ret = PyObject_CallFunction(py_complete, "sisi", prefix, n, line, x); PyObject *py_ret = PyObject_CallFunction(py_complete, "sisi", prefix, n, line, x);
PYW_GIL_RELEASE;
Py_DECREF(py_complete); Py_DECREF(py_complete);
@ -1124,7 +1204,9 @@ void enable_python_cli(bool enable)
// Prints the IDAPython copyright banner // Prints the IDAPython copyright banner
void py_print_banner() void py_print_banner()
{ {
PYW_GIL_ENSURE;
PyRun_SimpleString("print_banner()"); PyRun_SimpleString("print_banner()");
PYW_GIL_RELEASE;
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -1136,8 +1218,11 @@ static void install_python_menus()
// Add menu items for all the functions // Add menu items for all the functions
// Note: Different paths are used for the GUI version // Note: Different paths are used for the GUI version
add_menu_item("File/IDC command...", "P~y~thon command...", add_menu_item(
S_HOTKEY_RUNSTATEMENT, SETMENU_APP, "File/IDC command...",
"P~y~thon command...",
g_runstmt_hotkey,
SETMENU_APP,
IDAPython_Menu_Callback, IDAPython_Menu_Callback,
(void *)IDAPYTHON_RUNSTATEMENT); (void *)IDAPYTHON_RUNSTATEMENT);
@ -1277,6 +1362,19 @@ bool IDAPython_Init(void)
} }
#endif #endif
// Read configuration value
read_user_config_file("python.cfg", set_python_options, NULL);
if ( g_alert_auto_scripts )
{
const char *autofn = pywraps_check_autoscripts();
if ( autofn != NULL
&& askyn_c(0, "HIDECANCEL\nTITLE IDAPython\nThe script '%s' was found in the current directory and will be automatically executed by Python.\n\n"
"Do you want to continue loading IDAPython?", autofn) == 0 )
{
return false;
}
}
// Start the interpreter // Start the interpreter
Py_Initialize(); Py_Initialize();
if ( !Py_IsInitialized() ) if ( !Py_IsInitialized() )
@ -1285,16 +1383,22 @@ bool IDAPython_Init(void)
return false; return false;
} }
// Enable multi-threading support
if ( !PyEval_ThreadsInitialized() )
PyEval_InitThreads();
// Init the SWIG wrapper // Init the SWIG wrapper
init_idaapi(); init_idaapi();
// Set IDAPYTHON_VERSION in Python // Set IDAPYTHON_VERSION in Python
qsnprintf(tmp, sizeof(tmp), "IDAPYTHON_VERSION=(%d, %d, %d, '%s', %d)", \ qsnprintf(tmp, sizeof(tmp), "IDAPYTHON_VERSION=(%d, %d, %d, '%s', %d)\n"
"IDAPYTHON_REMOVE_CWD_SYS_PATH = %s\n",
VER_MAJOR, VER_MAJOR,
VER_MINOR, VER_MINOR,
VER_PATCH, VER_PATCH,
VER_STATUS, VER_STATUS,
VER_SERIAL); VER_SERIAL,
g_remove_cwd_sys_path ? "True" : "False");
PyRun_SimpleString(tmp); PyRun_SimpleString(tmp);
// Install extlang. Needs to be done before running init.py // Install extlang. Needs to be done before running init.py
@ -1302,11 +1406,11 @@ bool IDAPython_Init(void)
install_extlang(&extlang_python); install_extlang(&extlang_python);
// Execute init.py (for Python side initialization) // Execute init.py (for Python side initialization)
qmakepath(tmp, MAXSTR, g_idapython_dir, "init.py", NULL); qmakepath(tmp, MAXSTR, g_idapython_dir, S_INIT_PY, NULL);
if ( !PyRunFile(tmp) ) if ( !PyRunFile(tmp) )
{ {
handle_python_error(tmp, sizeof(tmp)); handle_python_error(tmp, sizeof(tmp));
warning("IDAPython: error executing init.py:\n%s", tmp); warning("IDAPython: error executing " S_INIT_PY ":\n%s", tmp);
return false; return false;
} }
@ -1357,18 +1461,18 @@ void IDAPython_Term(void)
del_menu_item("File/Python command..."); del_menu_item("File/Python command...");
g_menu_installed = false; g_menu_installed = false;
// Remove the CLI
enable_python_cli(false);
// Remove the extlang
remove_extlang(&extlang_python);
// Notify about IDA closing // Notify about IDA closing
pywraps_nw_notify(NW_TERMIDA_SLOT); pywraps_nw_notify(NW_TERMIDA_SLOT);
// De-init notify_when // De-init notify_when
pywraps_nw_term(); pywraps_nw_term();
// Remove the CLI
enable_python_cli(false);
// Remove the extlang
remove_extlang(&extlang_python);
// De-init pywraps // De-init pywraps
deinit_pywraps(); deinit_pywraps();
@ -1446,5 +1550,5 @@ plugin_t PLUGIN =
// the preferred short name of the plugin // the preferred short name of the plugin
S_IDAPYTHON, S_IDAPYTHON,
// the preferred hotkey to run the plugin // the preferred hotkey to run the plugin
S_HOTKEY_RUNSTATEMENT NULL
}; };

View File

@ -310,6 +310,37 @@ def FuncItems(start):
ok = fii.next_code() ok = fii.next_code()
def DecodePrecedingInstruction(ea):
"""
Decode preceding instruction in the execution flow.
@param ea: address to decode
@return: (None or the decode instruction, farref)
farref will contain 'true' if followed an xref, false otherwise
"""
prev_addr, farref = idaapi.decode_preceding_insn(ea)
if prev_addr == idaapi.BADADDR:
return (None, False)
else:
return (idaapi.cmd.copy(), farref)
def DecodePreviousInstruction(ea):
"""
Decodes the previous instruction and returns an insn_t like class
@param ea: address to decode
@return: None or a new insn_t instance
"""
inslen = idaapi.decode_prev_insn(ea)
if inslen == 0:
return None
return idaapi.cmd.copy()
def DecodeInstruction(ea): def DecodeInstruction(ea):
""" """
Decodes an instruction and returns an insn_t like class Decodes an instruction and returns an insn_t like class
@ -434,6 +465,7 @@ class Strings(object):
"""Clears the strings list cache""" """Clears the strings list cache"""
self.refresh(0, 0) # when ea1=ea2 the kernel will clear the cache self.refresh(0, 0) # when ea1=ea2 the kernel will clear the cache
def __init__(self, default_setup = True): def __init__(self, default_setup = True):
""" """
Initializes the Strings enumeration helper class Initializes the Strings enumeration helper class
@ -446,6 +478,7 @@ class Strings(object):
self._si = idaapi.string_info_t() self._si = idaapi.string_info_t()
def refresh(self, ea1=None, ea2=None): def refresh(self, ea1=None, ea2=None):
"""Refreshes the strings list""" """Refreshes the strings list"""
if ea1 is None: if ea1 is None:
@ -456,6 +489,7 @@ class Strings(object):
idaapi.refresh_strlist(ea1, ea2) idaapi.refresh_strlist(ea1, ea2)
self.size = idaapi.get_strlist_qty() self.size = idaapi.get_strlist_qty()
def setup(self, def setup(self,
strtypes = STR_C, strtypes = STR_C,
minlen = 5, minlen = 5,
@ -483,15 +517,24 @@ class Strings(object):
# Automatically refreshes # Automatically refreshes
self.refresh() self.refresh()
def _get_item(self, index):
if not idaapi.get_strlist_item(index, self._si):
return None
else:
return Strings.StringItem(self._si)
def __iter__(self):
return (self._get_item(index) for index in xrange(0, self.size))
def __getitem__(self, index): def __getitem__(self, index):
"""Returns a string item or None""" """Returns a string item or None"""
if index >= self.size: if index >= self.size:
raise StopIteration raise KeyError
else:
if idaapi.get_strlist_item(index, self._si): return self._get_item(index)
return Strings.StringItem(self._si)
return None
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
def GetIdbDir(): def GetIdbDir():
@ -646,6 +689,12 @@ class peutils_t(object):
def __str__(self): def __str__(self):
return "peutils_t(imagebase=%s, header=%s)" % (hex(self.imagebase), hex(self.header)) return "peutils_t(imagebase=%s, header=%s)" % (hex(self.imagebase), hex(self.header))
def header(self):
"""
Returns the complete PE header as an instance of peheader_t (defined in the SDK).
"""
return self.__penode.valobj()
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
cpu = _cpu() cpu = _cpu()
"""This is a special class instance used to access the registers as if they were attributes of this object. """This is a special class instance used to access the registers as if they were attributes of this object.

View File

@ -702,7 +702,7 @@ def MakeStr(ea, endea):
@note: The type of an existing string is returned by GetStringType() @note: The type of an existing string is returned by GetStringType()
""" """
return idaapi.make_ascii_string(ea, endea - ea, GetLongPrm(INF_STRTYPE)) return idaapi.make_ascii_string(ea, 0 if endea == BADADDR else endea - ea, GetLongPrm(INF_STRTYPE))
def MakeData(ea, flags, size, tid): def MakeData(ea, flags, size, tid):
@ -1710,7 +1710,7 @@ def Byte(ea):
might have more 1's. might have more 1's.
To check if a byte has a value, use functions hasValue(GetFlags(ea)) To check if a byte has a value, use functions hasValue(GetFlags(ea))
""" """
return idaapi.get_byte(ea) return idaapi.get_full_byte(ea)
def __DbgValue(ea, len): def __DbgValue(ea, len):
@ -1781,7 +1781,7 @@ def Word(ea):
If the current byte size is different from 8 bits, then the returned value If the current byte size is different from 8 bits, then the returned value
might have more 1's. might have more 1's.
""" """
return idaapi.get_word(ea) return idaapi.get_full_word(ea)
def Dword(ea): def Dword(ea):
@ -1792,7 +1792,7 @@ def Dword(ea):
@return: the value of the double word. If failed returns -1 @return: the value of the double word. If failed returns -1
""" """
return idaapi.get_long(ea) return idaapi.get_full_long(ea)
def Qword(ea): def Qword(ea):
@ -1802,10 +1802,8 @@ def Qword(ea):
@param ea: linear address @param ea: linear address
@return: the value of the quadro word. If failed, returns -1 @return: the value of the quadro word. If failed, returns -1
@note: this function is available only in the 64-bit version of IDA Pro
""" """
raise NotImplementedError, "will be implemented in the 64-bit version" return idaapi.get_qword(ea)
def GetFloat(ea): def GetFloat(ea):
@ -1839,7 +1837,7 @@ def LocByName(name):
@param name: name of program byte @param name: name of program byte
@return: address of the name @return: address of the name
badaddr - no such name BADADDR - No such name
""" """
return idaapi.get_name_ea(BADADDR, name) return idaapi.get_name_ea(BADADDR, name)
@ -1964,7 +1962,7 @@ def PrevAddr(ea):
return idaapi.prevaddr(ea) return idaapi.prevaddr(ea)
def NextHead(ea, maxea): def NextHead(ea, maxea=BADADDR):
""" """
Get next defined item (instruction or data) in the program Get next defined item (instruction or data) in the program
@ -1977,7 +1975,7 @@ def NextHead(ea, maxea):
return idaapi.next_head(ea, maxea) return idaapi.next_head(ea, maxea)
def PrevHead(ea, minea): def PrevHead(ea, minea=0):
""" """
Get previous defined item (instruction or data) in the program Get previous defined item (instruction or data) in the program
@ -2938,6 +2936,17 @@ def AskLong(defval, prompt):
return idaapi.asklong(defval, prompt) return idaapi.asklong(defval, prompt)
def ProcessUiAction(name, flags=0):
"""
Invokes an IDA Pro UI action by name
@param name: Command name
@param flags: Reserved. Must be zero
@return: Boolean
"""
return idaapi.process_ui_action(name, flags)
def AskSeg(defval, prompt): def AskSeg(defval, prompt):
""" """
Ask the user to enter a segment value Ask the user to enter a segment value
@ -3374,7 +3383,7 @@ def SegByName(segname):
if not seg: if not seg:
return BADADDR return BADADDR
return seg.startEA return seg.sel
def SetSegDefReg(ea, reg, value): def SetSegDefReg(ea, reg, value):
@ -6258,14 +6267,14 @@ def ParseType(inputtype, flags):
""" """
return idaapi.idc_parse_decl(idaapi.cvar.idati, inputtype, flags) return idaapi.idc_parse_decl(idaapi.cvar.idati, inputtype, flags)
def ParseTypes(inputtype, flags): def ParseTypes(inputtype, flags = 0):
""" """
Parse type declarations Parse type declarations
@param inputtype: file name or C declarations (depending on the flags) @param inputtype: file name or C declarations (depending on the flags)
@param flags: combination of PT_... constants or 0 @param flags: combination of PT_... constants or 0
@return: number of errors @return: number of parsing errors (0 no errors)
""" """
return idaapi.idc_parse_types(inputtype, flags) return idaapi.idc_parse_types(inputtype, flags)
@ -6790,7 +6799,6 @@ def GetProcessState():
""" """
return idaapi.get_process_state() return idaapi.get_process_state()
DSTATE_SUSP_FOR_EVENT = -2 # process is currently suspended to react to a debug event (not used)
DSTATE_SUSP = -1 # process is suspended DSTATE_SUSP = -1 # process is suspended
DSTATE_NOTASK = 0 # no process is currently debugged DSTATE_NOTASK = 0 # no process is currently debugged
DSTATE_RUN = 1 # process is running DSTATE_RUN = 1 # process is running
@ -7109,7 +7117,7 @@ def GetRegValue(name):
""" """
rv = idaapi.regval_t() rv = idaapi.regval_t()
res = idaapi.get_reg_val(name, rv) res = idaapi.get_reg_val(name, rv)
assert res, "get_reg_val() failed, bogus name perhaps?" assert res, "get_reg_val() failed, bogus register name ('%s') perhaps?" % name
return rv.ival return rv.ival
@ -7209,11 +7217,25 @@ BPTATTR_COUNT = 4
BPTATTR_FLAGS = 5 BPTATTR_FLAGS = 5
BPT_BRK = 0x01 # the debugger stops on this breakpoint BPT_BRK = 0x01 # the debugger stops on this breakpoint
BPT_TRACE = 0x02 # the debugger adds trace information when this breakpoint is reached BPT_TRACE = 0x02 # the debugger adds trace information when this breakpoint is reached
BPT_UPDMEM = 0x04 # update memory contents before evaluating bpt condition BPT_UPDMEM = 0x04 # refresh the memory layout and contents before evaluating bpt condition
BPT_UPDSEG = 0x08 # update memory config before evaluating bpt condition BPT_ENABLED = 0x08 # enabled?
BPT_LOWCND = 0x10 # condition is calculated at low level (on the server side)
BPTATTR_COND = 6 # Breakpoint condition. NOTE: the return value is a string in this case BPTATTR_COND = 6 # Breakpoint condition. NOTE: the return value is a string in this case
# Breakpoint location type:
BPLT_ABS = 0 # Absolute address. Attributes:
# - locinfo: absolute address
BPLT_REL = 1 # Module relative address. Attributes:
# - locpath: the module path
# - locinfo: offset from the module base address
BPLT_SYM = 2 # Symbolic name. The name will be resolved on DLL load/unload
# events and on naming an address. Attributes:
# - locpath: symbol name
# - locinfo: offset from the symbol base address
def SetBptAttr(address, bptattr, value): def SetBptAttr(address, bptattr, value):
""" """
@ -7530,16 +7552,44 @@ def WriteTxt(filepath, ea1, ea2):
def WriteExe(filepath): def WriteExe(filepath):
return GenerateFile(OFILE_EXE, filepath, 0, BADADDR, 0) return GenerateFile(OFILE_EXE, filepath, 0, BADADDR, 0)
def AddConst(enum_id,name,value): return AddConstEx(enum_id,name,value, idaapi.BADADDR)
def AddStruc(index,name): return AddStrucEx(index,name,0) UTP_STRUCT = idaapi.UTP_STRUCT
def AddUnion(index,name): return AddStrucEx(index,name,1) UTP_ENUM = idaapi.UTP_ENUM
def OpStroff(ea,n,strid): return OpStroffEx(ea,n,strid,0)
def OpEnum(ea,n,enumid): return OpEnumEx(ea,n,enumid,0)
def BeginTypeUpdating(utp):
"""
Begin type updating. Use this function if you
plan to call AddEnumConst or similar type modification functions
many times or from inside a loop
@param utp: one of UTP_xxxx consts
@return: None
"""
return idaapi.begin_type_updating(utp)
def EndTypeUpdating(utp):
"""
End type updating. Refreshes the type system
at the end of type modification operations
@param utp: one of idaapi.UTP_xxxx consts
@return: None
"""
return idaapi.end_type_updating(utp)
def AddConst(enum_id, name,value): return AddConstEx(enum_id, name, value, idaapi.BADADDR)
def AddStruc(index, name): return AddStrucEx(index,name, 0)
def AddUnion(index, name): return AddStrucEx(index,name, 1)
def OpStroff(ea, n, strid): return OpStroffEx(ea,n,strid, 0)
def OpEnum(ea, n, enumid): return OpEnumEx(ea,n,enumid, 0)
def DelConst(constid, v, mask): return DelConstEx(constid, v, 0, mask) def DelConst(constid, v, mask): return DelConstEx(constid, v, 0, mask)
def GetConst(constid, v, mask): return GetConstEx(constid, v, 0, mask) def GetConst(constid, v, mask): return GetConstEx(constid, v, 0, mask)
def AnalyseArea(sEA, eEA): return AnalyzeArea(sEA,eEA) def AnalyseArea(sEA, eEA): return AnalyzeArea(sEA,eEA)
def MakeStruct(ea,name): return MakeStructEx(ea, -1, name) def MakeStruct(ea, name): return MakeStructEx(ea, -1, name)
def Name(ea): return NameEx(BADADDR, ea) def Name(ea): return NameEx(BADADDR, ea)
def GetTrueName(ea): return GetTrueNameEx(BADADDR, ea) def GetTrueName(ea): return GetTrueNameEx(BADADDR, ea)
def MakeName(ea, name): return MakeNameEx(ea,name,SN_CHECK) def MakeName(ea, name): return MakeNameEx(ea,name,SN_CHECK)

View File

@ -31,7 +31,7 @@ class IDAPythonStdOut:
# Swap out the unprintable characters # Swap out the unprintable characters
text = text.decode('ascii', 'replace').encode('ascii', 'replace') text = text.decode('ascii', 'replace').encode('ascii', 'replace')
# Print to IDA message window # Print to IDA message window
_idaapi.msg(text.replace("%", "%%")) _idaapi.msg(text)
def flush(self): def flush(self):
pass pass
@ -61,9 +61,9 @@ def print_banner():
] ]
sepline = '-' * (max([len(s) for s in banner])+1) sepline = '-' * (max([len(s) for s in banner])+1)
print sepline print(sepline)
print "\n".join(banner) print("\n".join(banner))
print sepline print(sepline)
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
@ -76,8 +76,19 @@ sys.argv = [""]
# Have to make sure Python finds our modules # Have to make sure Python finds our modules
sys.path.append(_idaapi.idadir("python")) sys.path.append(_idaapi.idadir("python"))
# Remove current directory from the top of the patch search
if '' in sys.path: # On non Windows, the empty path is added
sys.path.remove('')
if os.getcwd() in sys.path:
sys.path.remove(os.getcwd())
# ...and add it to the end if needed
if not IDAPYTHON_REMOVE_CWD_SYS_PATH:
sys.path.append(os.getcwd())
# Import all the required modules # Import all the required modules
from idaapi import Choose, get_user_idadir, cvar, Choose2, Appcall from idaapi import Choose, get_user_idadir, cvar, Choose2, Appcall, Form
from idc import * from idc import *
from idautils import * from idautils import *
import idaapi import idaapi

View File

@ -5,6 +5,7 @@
// Types // Types
#ifndef PYUL_DEFINED #ifndef PYUL_DEFINED
#define PYUL_DEFINED #define PYUL_DEFINED
typedef unsigned PY_LONG_LONG PY_ULONG_LONG;
#ifdef __EA64__ #ifdef __EA64__
typedef unsigned PY_LONG_LONG pyul_t; typedef unsigned PY_LONG_LONG pyul_t;
typedef PY_LONG_LONG pyl_t; typedef PY_LONG_LONG pyl_t;
@ -56,6 +57,31 @@ typedef qvector<PyObject *> ppyobject_vec_t;
#define CIP_OK 1 // Success #define CIP_OK 1 // Success
#define CIP_OK_NODECREF 2 // Success but do not decrement its reference #define CIP_OK_NODECREF 2 // Success but do not decrement its reference
//---------------------------------------------------------------------------
class CGilStateAuto
{
private:
PyGILState_STATE state;
public:
CGilStateAuto()
{
state = PyGILState_Ensure();
}
~CGilStateAuto()
{
PyGILState_Release(state);
}
};
// Declare a variable to acquire/release the GIL
#define PYW_GIL_AUTO_ENSURE CGilStateAuto GIL_STATE_AUTO
// Macros to acquire/release GIL in a given scope
#define PYW_GIL_ENSURE_N(name) PyGILState_STATE gil_state##name = PyGILState_Ensure()
#define PYW_GIL_RELEASE_N(name) PyGILState_Release(gil_state##name)
#define PYW_GIL_ENSURE PYW_GIL_ENSURE_N(_)
#define PYW_GIL_RELEASE PYW_GIL_RELEASE_N(_)
//------------------------------------------------------------------------ //------------------------------------------------------------------------
// All the exported functions from PyWraps are forward declared here // All the exported functions from PyWraps are forward declared here
insn_t *insn_t_get_clink(PyObject *self); insn_t *insn_t_get_clink(PyObject *self);
@ -86,7 +112,8 @@ bool PyW_IsSequenceType(PyObject *obj);
bool PyW_GetError(qstring *out = NULL); bool PyW_GetError(qstring *out = NULL);
// If an error occured (it calls PyGetError) it displays it and return TRUE // If an error occured (it calls PyGetError) it displays it and return TRUE
bool PyW_ShowErr(const char *cb_name); // This function is used when calling callbacks
bool PyW_ShowCbErr(const char *cb_name);
// Utility function to create a class instance whose constructor takes zero arguments // Utility function to create a class instance whose constructor takes zero arguments
PyObject *create_idaapi_class_instance0(const char *clsname); PyObject *create_idaapi_class_instance0(const char *clsname);
@ -124,6 +151,12 @@ Py_ssize_t pyvar_walk_list(
int (idaapi *cb)(PyObject *py_item, Py_ssize_t index, void *ud) = NULL, int (idaapi *cb)(PyObject *py_item, Py_ssize_t index, void *ud) = NULL,
void *ud = NULL); void *ud = NULL);
// Converts an intvec_t to a Python list object
PyObject *PyW_IntVecToPyList(const intvec_t &intvec);
// Converts an Python list to an intvec
void PyW_PyListToIntVec(PyObject *py_list, intvec_t &intvec);
// Returns a reference to a class // Returns a reference to a class
PyObject *get_idaapi_attr(const char *attr); PyObject *get_idaapi_attr(const char *attr);
@ -132,4 +165,6 @@ bool pywraps_nw_term();
bool pywraps_nw_notify(int slot, ...); bool pywraps_nw_notify(int slot, ...);
bool pywraps_nw_init(); bool pywraps_nw_init();
const char *pywraps_check_autoscripts();
#endif #endif

View File

@ -101,7 +101,9 @@
static bool idaapi py_testf_cb(flags_t flags, void *ud) static bool idaapi py_testf_cb(flags_t flags, void *ud)
{ {
PyObject *py_flags = PyLong_FromUnsignedLong(flags); PyObject *py_flags = PyLong_FromUnsignedLong(flags);
PYW_GIL_ENSURE;
PyObject *result = PyObject_CallFunctionObjArgs((PyObject *) ud, py_flags, NULL); PyObject *result = PyObject_CallFunctionObjArgs((PyObject *) ud, py_flags, NULL);
PYW_GIL_RELEASE;
bool ret = result != NULL && PyObject_IsTrue(result); bool ret = result != NULL && PyObject_IsTrue(result);
Py_XDECREF(result); Py_XDECREF(result);
Py_XDECREF(py_flags); Py_XDECREF(py_flags);
@ -114,6 +116,7 @@ static ea_t py_npthat(ea_t ea, ea_t bound, PyObject *py_callable, bool next)
{ {
if ( !PyCallable_Check(py_callable) ) if ( !PyCallable_Check(py_callable) )
return BADADDR; return BADADDR;
else
return (next ? nextthat : prevthat)(ea, bound, py_testf_cb, py_callable); return (next ? nextthat : prevthat)(ea, bound, py_testf_cb, py_callable);
} }
@ -134,8 +137,17 @@ class py_custom_data_type_t
size_t nbytes) // size of the future item size_t nbytes) // size of the future item
{ {
py_custom_data_type_t *_this = (py_custom_data_type_t *)ud; py_custom_data_type_t *_this = (py_custom_data_type_t *)ud;
PyObject *py_result = PyObject_CallMethod(_this->py_self, (char *)S_MAY_CREATE_AT, PY_FMT64 PY_FMT64, pyul_t(ea), pyul_t(nbytes));
PyW_ShowErr(S_MAY_CREATE_AT); PYW_GIL_ENSURE;
PyObject *py_result = PyObject_CallMethod(
_this->py_self,
(char *)S_MAY_CREATE_AT,
PY_FMT64 PY_FMT64,
pyul_t(ea),
pyul_t(nbytes));
PYW_GIL_RELEASE;
PyW_ShowCbErr(S_MAY_CREATE_AT);
bool ok = py_result != NULL && PyObject_IsTrue(py_result); bool ok = py_result != NULL && PyObject_IsTrue(py_result);
Py_XDECREF(py_result); Py_XDECREF(py_result);
return ok; return ok;
@ -152,9 +164,18 @@ class py_custom_data_type_t
// Returns: 0-no such item can be created/displayed // Returns: 0-no such item can be created/displayed
// this callback is required only for varsize datatypes // this callback is required only for varsize datatypes
py_custom_data_type_t *_this = (py_custom_data_type_t *)ud; py_custom_data_type_t *_this = (py_custom_data_type_t *)ud;
PyObject *py_result = PyObject_CallMethod(_this->py_self, (char *)S_CALC_ITEM_SIZE, PY_FMT64 PY_FMT64, pyul_t(ea), pyul_t(maxsize)); PYW_GIL_ENSURE;
if ( PyW_ShowErr(S_CALC_ITEM_SIZE) || py_result == NULL ) PyObject *py_result = PyObject_CallMethod(
_this->py_self,
(char *)S_CALC_ITEM_SIZE,
PY_FMT64 PY_FMT64,
pyul_t(ea),
pyul_t(maxsize));
PYW_GIL_RELEASE;
if ( PyW_ShowCbErr(S_CALC_ITEM_SIZE) || py_result == NULL )
return 0; return 0;
uint64 num = 0; uint64 num = 0;
PyW_GetNumber(py_result, &num); PyW_GetNumber(py_result, &num);
Py_XDECREF(py_result); Py_XDECREF(py_result);
@ -189,6 +210,7 @@ public:
// name // name
if ( !PyW_GetStringAttr(py_obj, S_NAME, &dt_name) ) if ( !PyW_GetStringAttr(py_obj, S_NAME, &dt_name) )
break; break;
dt.name = dt_name.c_str(); dt.name = dt_name.c_str();
// menu_name (optional) // menu_name (optional)
@ -293,11 +315,14 @@ private:
int dtid) // custom data type id int dtid) // custom data type id
{ {
// Build a string from the buffer // Build a string from the buffer
PyObject *py_value = PyString_FromStringAndSize((const char *)value, Py_ssize_t(size)); PyObject *py_value = PyString_FromStringAndSize(
(const char *)value,
Py_ssize_t(size));
if ( py_value == NULL ) if ( py_value == NULL )
return false; return false;
py_custom_data_format_t *_this = (py_custom_data_format_t *) ud; py_custom_data_format_t *_this = (py_custom_data_format_t *) ud;
PYW_GIL_ENSURE;
PyObject *py_result = PyObject_CallMethod( PyObject *py_result = PyObject_CallMethod(
_this->py_self, _this->py_self,
(char *)S_PRINTF, (char *)S_PRINTF,
@ -306,11 +331,12 @@ private:
pyul_t(current_ea), pyul_t(current_ea),
operand_num, operand_num,
dtid); dtid);
PYW_GIL_RELEASE;
// Done with the string // Done with the string
Py_DECREF(py_value); Py_DECREF(py_value);
// Error while calling the function? // Error while calling the function?
if ( PyW_ShowErr(S_PRINTF) || py_result == NULL ) if ( PyW_ShowCbErr(S_PRINTF) || py_result == NULL )
return false; return false;
bool ok = false; bool ok = false;
@ -338,6 +364,7 @@ private:
qstring *errstr) // buffer for error message qstring *errstr) // buffer for error message
{ {
py_custom_data_format_t *_this = (py_custom_data_format_t *) ud; py_custom_data_format_t *_this = (py_custom_data_format_t *) ud;
PYW_GIL_ENSURE;
PyObject *py_result = PyObject_CallMethod( PyObject *py_result = PyObject_CallMethod(
_this->py_self, _this->py_self,
(char *)S_SCAN, (char *)S_SCAN,
@ -345,9 +372,10 @@ private:
input, input,
pyul_t(current_ea), pyul_t(current_ea),
operand_num); operand_num);
PYW_GIL_RELEASE;
// Error while calling the function? // Error while calling the function?
if ( PyW_ShowErr(S_SCAN) || py_result == NULL) if ( PyW_ShowCbErr(S_SCAN) || py_result == NULL)
return false; return false;
bool ok = false; bool ok = false;
@ -356,6 +384,7 @@ private:
// We expect a tuple(bool, string|None) // We expect a tuple(bool, string|None)
if ( !PyTuple_Check(py_result) || PyTuple_Size(py_result) != 2 ) if ( !PyTuple_Check(py_result) || PyTuple_Size(py_result) != 2 )
break; break;
// Borrow references // Borrow references
PyObject *py_bool = PyTuple_GetItem(py_result, 0); PyObject *py_bool = PyTuple_GetItem(py_result, 0);
PyObject *py_val = PyTuple_GetItem(py_result, 1); PyObject *py_val = PyTuple_GetItem(py_result, 1);
@ -404,8 +433,17 @@ private:
// this callback may be missing. // this callback may be missing.
{ {
py_custom_data_format_t *_this = (py_custom_data_format_t *) ud; py_custom_data_format_t *_this = (py_custom_data_format_t *) ud;
PyObject *py_result = PyObject_CallMethod(_this->py_self, (char *)S_ANALYZE, PY_FMT64 "i", pyul_t(current_ea),operand_num);
PyW_ShowErr(S_ANALYZE); PYW_GIL_ENSURE;
PyObject *py_result = PyObject_CallMethod(
_this->py_self,
(char *)S_ANALYZE,
PY_FMT64 "i",
pyul_t(current_ea),
operand_num);
PYW_GIL_RELEASE;
PyW_ShowCbErr(S_ANALYZE);
Py_XDECREF(py_result); Py_XDECREF(py_result);
} }
public: public:
@ -415,7 +453,10 @@ public:
py_self = NULL; py_self = NULL;
} }
const char *get_name() const { return df_name.c_str(); } const char *get_name() const
{
return df_name.c_str();
}
int register_df(int dtid, PyObject *py_obj) int register_df(int dtid, PyObject *py_obj)
{ {
@ -491,9 +532,11 @@ public:
Py_INCREF(py_obj); Py_INCREF(py_obj);
py_self = py_obj; py_self = py_obj;
// Update the format ID
py_attr = PyInt_FromLong(dfid); py_attr = PyInt_FromLong(dfid);
PyObject_SetAttrString(py_obj, S_ID, py_attr); PyObject_SetAttrString(py_obj, S_ID, py_attr);
Py_DECREF(py_attr); Py_DECREF(py_attr);
py_attr = NULL; py_attr = NULL;
} while ( false ); } while ( false );

View File

@ -10,8 +10,14 @@ typedef struct
%ignore source_file_t; %ignore source_file_t;
%ignore source_item_t; %ignore source_item_t;
%ignore srcinfo_provider_t; %ignore srcinfo_provider_t;
%ignore bpt_location_t::print;
%ignore bpt_t::set_cond;
%ignore bpt_t::eval_cond;
%ignore bpt_t::write;
%ignore bpt_t::erase;
%rename (get_manual_regions) py_get_manual_regions; %rename (get_manual_regions) py_get_manual_regions;
%ignore set_manual_regions; %ignore set_manual_regions;
%ignore inform_idc_about_debthread;
%include "dbg.hpp" %include "dbg.hpp"
%ignore DBG_Callback; %ignore DBG_Callback;
%feature("director") DBG_Hooks; %feature("director") DBG_Hooks;
@ -75,8 +81,12 @@ static PyObject *refresh_debugger_memory()
{ {
invalidate_dbgmem_config(); invalidate_dbgmem_config();
invalidate_dbgmem_contents(BADADDR, 0); invalidate_dbgmem_contents(BADADDR, 0);
// Ask the debugger to populate debug names
if ( dbg != NULL && dbg->stopped_at_debug_event != NULL ) if ( dbg != NULL && dbg->stopped_at_debug_event != NULL )
dbg->stopped_at_debug_event(true); dbg->stopped_at_debug_event(true);
// Invalidate the cache
isEnabled(0); isEnabled(0);
Py_RETURN_NONE; Py_RETURN_NONE;

View File

@ -49,7 +49,12 @@
int idaapi py_enumerate_files_cb(const char *file, void *ud) int idaapi py_enumerate_files_cb(const char *file, void *ud)
{ {
PyObject *py_file = PyString_FromString(file); PyObject *py_file = PyString_FromString(file);
PyObject *py_ret = PyObject_CallFunctionObjArgs((PyObject *)ud, py_file, NULL); PYW_GIL_ENSURE;
PyObject *py_ret = PyObject_CallFunctionObjArgs(
(PyObject *)ud,
py_file,
NULL);
PYW_GIL_RELEASE;
int r = (py_ret == NULL || !PyNumber_Check(py_ret)) ? 1 /* stop enumeration on failure */ : PyInt_AsLong(py_ret); int r = (py_ret == NULL || !PyNumber_Check(py_ret)) ? 1 /* stop enumeration on failure */ : PyInt_AsLong(py_ret);
Py_XDECREF(py_file); Py_XDECREF(py_file);
Py_XDECREF(py_ret); Py_XDECREF(py_ret);

View File

@ -35,15 +35,17 @@
%ignore expr_printf; %ignore expr_printf;
%ignore expr_sprintf; %ignore expr_sprintf;
%ignore expr_printfer; %ignore expr_printfer;
%ignore idaapi init_idc; %ignore init_idc;
%ignore idaapi term_idc; %ignore term_idc;
%ignore del_idc_userfuncs; %ignore create_default_idc_classes;
%ignore del_idc_userdefs; %ignore insn_to_idc;
%ignore find_builtin_idc_func; %ignore find_builtin_idc_func;
%ignore idc_mutex;
%ignore idc_lx; %ignore idc_lx;
%ignore idc_vars; %ignore idc_vars;
%ignore idc_resolve_label; %ignore idc_resolve_label;
%ignore idc_resolver_ea; %ignore idc_resolver_ea;
%ignore setup_lowcnd_regfuncs;
%cstring_output_maxstr_none(char *errbuf, size_t errbufsize); %cstring_output_maxstr_none(char *errbuf, size_t errbufsize);
@ -83,12 +85,13 @@ bool calc_idc_expr_wrap(ea_t where,const char *line, idc_value_t *rv, char *errb
%} %}
%ignore CompileLine(const char *line, char *errbuf, size_t errbufsize, uval_t (idaapi*_getname)(const char *name)=NULL); %ignore CompileLine(const char *line, char *errbuf, size_t errbufsize, uval_t (idaapi*_getname)(const char *name)=NULL);
%ignore CompileLineEx;
%rename (CompileLine) CompileLine_wrap; %rename (CompileLine) CompileLine_wrap;
%inline %{ %inline %{
bool CompileLine_wrap(const char *line, char *errbuf, size_t errbufsize) bool CompileLine_wrap(const char *line, char *errbuf, size_t errbufsize)
{ {
return !CompileLine(line, errbuf, errbufsize); return !CompileLineEx(line, errbuf, errbufsize);
} }
%} %}

View File

@ -27,6 +27,7 @@
%ignore create_func_eas_array; %ignore create_func_eas_array;
%ignore auto_add_func_tails; %ignore auto_add_func_tails;
%ignore read_tails; %ignore read_tails;
%rename (get_idasgn_desc) py_get_idasgn_desc;
%include "funcs.hpp" %include "funcs.hpp"
@ -34,18 +35,47 @@
%clear(char *optlibs); %clear(char *optlibs);
%inline %{ %inline %{
//-----------------------------------------------------------------------
/* /*
#<pydoc> #<pydoc>
def get_fchunk_referer(ea, idx): def get_fchunk_referer(ea, idx):
pass pass
#</pydoc> #</pydoc>
*/ */
ea_t get_fchunk_referer(ea_t ea, size_t idx) static ea_t get_fchunk_referer(ea_t ea, size_t idx)
{ {
func_t *pfn = get_fchunk(ea); func_t *pfn = get_fchunk(ea);
func_parent_iterator_t dummy(pfn); // read referer info func_parent_iterator_t dummy(pfn); // read referer info
if (idx >= pfn->refqty || pfn->referers == NULL) if (idx >= pfn->refqty || pfn->referers == NULL)
return BADADDR; return BADADDR;
else
return pfn->referers[idx]; return pfn->referers[idx];
} }
//-----------------------------------------------------------------------
/*
#<pydoc>
def get_idasgn_desc(n):
"""
Get information about a signature in the list.
It returns both:
signame - the name of the signature
optlibs - the names of the optional libraries
@param n: number of signature in the list (0..get_idasgn_qty()-1)
@return: None on failure or tuple(signame, optlibs)
"""
#</pydoc>
*/
static PyObject *ida_export py_get_idasgn_desc(int n)
{
char signame[MAXSTR];
char optlibs[MAXSTR];
if ( get_idasgn_desc(n, signame, sizeof(signame), optlibs, sizeof(optlibs)) == -1 )
Py_RETURN_NONE;
else
return Py_BuildValue("(ss)", signame, optlibs);
}
%} %}

View File

@ -91,6 +91,14 @@ class FlowChart(object):
self._q.refresh() self._q.refresh()
def _getitem(self, index):
return BasicBlock(index, self._q[index], self)
def __iter__(self):
return (self._getitem(index) for index in xrange(0, self.size))
def __getitem__(self, index): def __getitem__(self, index):
""" """
Returns a basic block Returns a basic block
@ -98,9 +106,9 @@ class FlowChart(object):
@return: BasicBlock @return: BasicBlock
""" """
if index >= self.size: if index >= self.size:
raise StopIteration raise KeyError
else: else:
return BasicBlock(index, self._q[index], self) return self._getitem(index)
#</pycode(py_gdl)> #</pycode(py_gdl)>
%} %}

View File

@ -2,26 +2,6 @@
%ignore graph_visitor_t; %ignore graph_visitor_t;
%ignore abstract_graph_t; %ignore abstract_graph_t;
%{
#ifdef __GNUC__
// for some reason GCC insists on putting the vtable into the object file,
// even though we only use mutable_graph_t by pointer
// so we define these methods here to make the linker happy
edge_info_t *idaapi mutable_graph_t::get_edge(edge_t e) { INTERR(); };
mutable_graph_t *idaapi mutable_graph_t::clone(void) const { INTERR(); };
bool idaapi mutable_graph_t::redo_layout(void) { INTERR(); };
void idaapi mutable_graph_t::resize(int n) { INTERR(); };
int idaapi mutable_graph_t::add_node(const rect_t *r) { INTERR(); };
ssize_t idaapi mutable_graph_t::del_node(int n) { INTERR(); };
bool idaapi mutable_graph_t::add_edge(int i, int j, const edge_info_t *ei) { INTERR(); };
bool idaapi mutable_graph_t::del_edge(int i, int j) { INTERR(); };
bool idaapi mutable_graph_t::replace_edge(int i, int j, int x, int y) { INTERR(); };
bool idaapi mutable_graph_t::refresh(void) { INTERR(); };
bool idaapi mutable_graph_t::set_nrect(int n, const rect_t &r) { INTERR(); };
#endif
%}
%{ %{
//<code(py_graph)> //<code(py_graph)>
class py_graph_t class py_graph_t
@ -46,6 +26,7 @@ private:
nodetext_cache_t(const char *t, bgcolor_t c): text(t), bgcolor(c) { } nodetext_cache_t(const char *t, bgcolor_t c): text(t), bgcolor(c) { }
nodetext_cache_t() { } nodetext_cache_t() { }
}; };
class nodetext_cache_map_t: public std::map<int, nodetext_cache_t> class nodetext_cache_map_t: public std::map<int, nodetext_cache_t>
{ {
public: public:
@ -75,6 +56,7 @@ private:
(*this)[form] = py; (*this)[form] = py;
} }
}; };
class cmdid_map_t: public std::map<Py_ssize_t, py_graph_t *> class cmdid_map_t: public std::map<Py_ssize_t, py_graph_t *>
{ {
private: private:
@ -83,7 +65,8 @@ private:
cmdid_map_t() cmdid_map_t()
{ {
uid = 1; // we start by one and keep zero for error id // We start by one and keep zero for error id
uid = 1;
} }
void add(py_graph_t *pyg) void add(py_graph_t *pyg)
@ -92,7 +75,10 @@ private:
++uid; ++uid;
} }
const Py_ssize_t id() const { return uid; } const Py_ssize_t id() const
{
return uid;
}
void clear(py_graph_t *pyg) void clear(py_graph_t *pyg)
{ {
@ -108,6 +94,7 @@ private:
++it; ++it;
} }
} }
py_graph_t *get(Py_ssize_t id) py_graph_t *get(Py_ssize_t id)
{ {
iterator it = find(id); iterator it = find(id);
@ -136,13 +123,16 @@ private:
py_graph_t *_this = cmdid_pyg.get(id); py_graph_t *_this = cmdid_pyg.get(id);
if ( _this != NULL ) if ( _this != NULL )
_this->on_command(id); _this->on_command(id);
return true; return true;
} }
void on_command(Py_ssize_t id) void on_command(Py_ssize_t id)
{ {
// Check return value to OnRefresh() call // Check return value to OnRefresh() call
PYW_GIL_ENSURE;
PyObject *ret = PyObject_CallMethod(self, (char *)S_ON_COMMAND, "n", id); PyObject *ret = PyObject_CallMethod(self, (char *)S_ON_COMMAND, "n", id);
PYW_GIL_RELEASE;
Py_XDECREF(ret); Py_XDECREF(ret);
} }
@ -155,7 +145,9 @@ private:
return; return;
// Check return value to OnRefresh() call // Check return value to OnRefresh() call
PYW_GIL_ENSURE;
PyObject *ret = PyObject_CallMethod(self, (char *)S_ON_REFRESH, NULL); PyObject *ret = PyObject_CallMethod(self, (char *)S_ON_REFRESH, NULL);
PYW_GIL_RELEASE;
if ( ret == NULL || !PyObject_IsTrue(ret) ) if ( ret == NULL || !PyObject_IsTrue(ret) )
{ {
Py_XDECREF(ret); Py_XDECREF(ret);
@ -213,11 +205,14 @@ private:
Py_DECREF(id); Py_DECREF(id);
if ( v > max_nodes ) if ( v > max_nodes )
break; break;
edge_ids[j] = v; edge_ids[j] = v;
} }
// Incomplete? // Incomplete?
if ( j != qnumber(edge_ids) ) if ( j != qnumber(edge_ids) )
break; break;
// Add the edge // Add the edge
g->add_edge(edge_ids[0], edge_ids[1], NULL); g->add_edge(edge_ids[0], edge_ids[1], NULL);
} }
@ -240,7 +235,9 @@ private:
} }
// Not cached, call Python // Not cached, call Python
PYW_GIL_ENSURE;
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_GETTEXT, "i", node); PyObject *result = PyObject_CallMethod(self, (char *)S_ON_GETTEXT, "i", node);
PYW_GIL_RELEASE;
if ( result == NULL ) if ( result == NULL )
return false; return false;
@ -276,6 +273,7 @@ private:
*str = c->text.c_str(); *str = c->text.c_str();
if ( bg_color != NULL ) if ( bg_color != NULL )
*bg_color = c->bgcolor; *bg_color = c->bgcolor;
return true; return true;
} }
@ -290,7 +288,9 @@ private:
if ( mousenode == -1 ) if ( mousenode == -1 )
return 0; return 0;
PYW_GIL_ENSURE;
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_HINT, "i", mousenode); PyObject *result = PyObject_CallMethod(self, (char *)S_ON_HINT, "i", mousenode);
PYW_GIL_RELEASE;
bool ok = result != NULL && PyString_Check(result); bool ok = result != NULL && PyString_Check(result);
if ( !ok ) if ( !ok )
{ {
@ -307,24 +307,33 @@ private:
{ {
if ( self != NULL ) if ( self != NULL )
{ {
if ( cb_flags & GR_HAVE_CLOSE ) if ( (cb_flags & GR_HAVE_CLOSE) != 0 )
{ {
PYW_GIL_ENSURE;
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_CLOSE, NULL); PyObject *result = PyObject_CallMethod(self, (char *)S_ON_CLOSE, NULL);
PYW_GIL_RELEASE;
Py_XDECREF(result); Py_XDECREF(result);
} }
unbind(); unbind();
} }
// Remove the TForm from list // Remove the TForm from list
if ( form != NULL ) if ( form != NULL )
tform_pyg.erase(form); tform_pyg.erase(form);
// remove all associated commands from the list
// Remove all associated commands from the list
cmdid_pyg.clear(this); cmdid_pyg.clear(this);
// Delete this instance // Delete this instance
delete this; delete this;
} }
// graph is being clicked // graph is being clicked
int on_clicked(graph_viewer_t * /*gv*/, selection_item_t * /*item1*/, graph_item_t *item2) int on_clicked(
graph_viewer_t * /*gv*/,
selection_item_t * /*item1*/,
graph_item_t *item2)
{ {
// in: graph_viewer_t *gv // in: graph_viewer_t *gv
// selection_item_t *current_item1 // selection_item_t *current_item1
@ -338,7 +347,14 @@ private:
if ( item2->n == -1 ) if ( item2->n == -1 )
return 1; return 1;
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_CLICK, "i", item2->n); PYW_GIL_ENSURE;
PyObject *result = PyObject_CallMethod(
self,
(char *)S_ON_CLICK,
"i",
item2->n);
PYW_GIL_RELEASE;
if ( result == NULL || !PyObject_IsTrue(result) ) if ( result == NULL || !PyObject_IsTrue(result) )
{ {
Py_XDECREF(result); Py_XDECREF(result);
@ -360,7 +376,15 @@ private:
//selection_item_t *s = va_arg(va, selection_item_t *); //selection_item_t *s = va_arg(va, selection_item_t *);
if ( item == NULL || !item->is_node ) if ( item == NULL || !item->is_node )
return 1; return 1;
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_DBL_CLICK, "i", item->node);
PYW_GIL_ENSURE;
PyObject *result = PyObject_CallMethod(
self,
(char *)S_ON_DBL_CLICK,
"i",
item->node);
PYW_GIL_RELEASE;
if ( result == NULL || !PyObject_IsTrue(result) ) if ( result == NULL || !PyObject_IsTrue(result) )
{ {
Py_XDECREF(result); Py_XDECREF(result);
@ -373,14 +397,25 @@ private:
// a graph viewer got focus // a graph viewer got focus
void on_gotfocus(graph_viewer_t * /*gv*/) void on_gotfocus(graph_viewer_t * /*gv*/)
{ {
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_ACTIVATE, NULL); PYW_GIL_ENSURE;
PyObject *result = PyObject_CallMethod(
self,
(char *)S_ON_ACTIVATE,
NULL);
PYW_GIL_RELEASE;
Py_XDECREF(result); Py_XDECREF(result);
} }
// a graph viewer lost focus // a graph viewer lost focus
void on_lostfocus(graph_viewer_t *gv) void on_lostfocus(graph_viewer_t *gv)
{ {
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_DEACTIVATE, NULL); PYW_GIL_ENSURE;
PyObject *result = PyObject_CallMethod(
self,
(char *)S_ON_DEACTIVATE,
NULL);
PYW_GIL_RELEASE;
Py_XDECREF(result); Py_XDECREF(result);
} }
@ -392,7 +427,15 @@ private:
// out: 0-ok, 1-forbid to change the current node // out: 0-ok, 1-forbid to change the current node
if ( curnode < 0 ) if ( curnode < 0 )
return 0; return 0;
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_SELECT, "i", curnode);
PYW_GIL_ENSURE;
PyObject *result = PyObject_CallMethod(
self,
(char *)S_ON_SELECT,
"i",
curnode);
PYW_GIL_RELEASE;
bool allow = (result != NULL && PyObject_IsTrue(result)); bool allow = (result != NULL && PyObject_IsTrue(result));
Py_XDECREF(result); Py_XDECREF(result);
return allow ? 0 : 1; return allow ? 0 : 1;
@ -428,7 +471,10 @@ private:
ret = on_clicked(gv, item, gitem); ret = on_clicked(gv, item, gitem);
} }
else else
ret = 1; // ignore click {
// Ignore the click
ret = 1;
}
break; break;
// //
case grcode_dblclicked: case grcode_dblclicked:
@ -445,17 +491,20 @@ private:
case grcode_gotfocus: case grcode_gotfocus:
if ( cb_flags & GR_HAVE_GOTFOCUS ) if ( cb_flags & GR_HAVE_GOTFOCUS )
on_gotfocus(va_arg(va, graph_viewer_t *)); on_gotfocus(va_arg(va, graph_viewer_t *));
ret = 0; ret = 0;
break; break;
// //
case grcode_lostfocus: case grcode_lostfocus:
if ( cb_flags & GR_HAVE_LOSTFOCUS ) if ( cb_flags & GR_HAVE_LOSTFOCUS )
on_lostfocus(va_arg(va, graph_viewer_t *)); on_lostfocus(va_arg(va, graph_viewer_t *));
ret = 0; ret = 0;
break; break;
// //
case grcode_user_refresh: case grcode_user_refresh:
on_user_refresh(va_arg(va, mutable_graph_t *)); on_user_refresh(va_arg(va, mutable_graph_t *));
ret = 1; ret = 1;
break; break;
// //
@ -617,7 +666,7 @@ private:
netnode id; netnode id;
id.create(); id.create();
gv = create_graph_viewer(form, id, s_callback, this, 0); gv = create_graph_viewer(form, id, s_callback, this, 0);
open_tform(form, FORM_MDI|FORM_TAB|FORM_MENU); open_tform(form, FORM_MDI | FORM_TAB | FORM_MENU);
if ( gv != NULL ) if ( gv != NULL )
viewer_fit_window(gv); viewer_fit_window(gv);
} }
@ -625,6 +674,7 @@ private:
{ {
show(); show();
} }
viewer_fit_window(gv); viewer_fit_window(gv);
return 0; return 0;
} }
@ -655,6 +705,7 @@ private:
py_graph_t *_this = extract_this(self); py_graph_t *_this = extract_this(self);
if ( _this == NULL || _this->form == NULL ) if ( _this == NULL || _this->form == NULL )
return; return;
_this->jump_to_node(0); _this->jump_to_node(0);
} }
@ -663,6 +714,7 @@ private:
py_graph_t *_this = extract_this(self); py_graph_t *_this = extract_this(self);
if ( _this == NULL || _this->form == NULL ) if ( _this == NULL || _this->form == NULL )
return 0; return 0;
return _this->add_command(title, hotkey); return _this->add_command(title, hotkey);
} }
@ -671,6 +723,7 @@ private:
py_graph_t *_this = extract_this(self); py_graph_t *_this = extract_this(self);
if ( _this == NULL || _this->form == NULL ) if ( _this == NULL || _this->form == NULL )
return; return;
close_tform(_this->form, 0); close_tform(_this->form, 0);
} }
@ -679,6 +732,7 @@ private:
py_graph_t *_this = extract_this(self); py_graph_t *_this = extract_this(self);
if ( _this == NULL ) if ( _this == NULL )
return; return;
_this->refresh(); _this->refresh();
} }
@ -763,7 +817,7 @@ bool pyg_show(PyObject *self);
%pythoncode %{ %pythoncode %{
#<pycode(py_graph)> #<pycode(py_graph)>
class GraphViewer: class GraphViewer(object):
"""This class wraps the user graphing facility provided by the graph.hpp file""" """This class wraps the user graphing facility provided by the graph.hpp file"""
def __init__(self, title, close_open = False): def __init__(self, title, close_open = False):
""" """
@ -793,10 +847,16 @@ class GraphViewer:
self._nodes = [] self._nodes = []
self._edges = [] self._edges = []
def __iter__(self):
return (self._nodes[index] for index in xrange(0, len(self._nodes)))
def __getitem__(self, idx): def __getitem__(self, idx):
"""Returns a reference to the object associated with this node id""" """Returns a reference to the object associated with this node id"""
if idx > len(self._nodes): if idx >= len(self._nodes):
raise StopIteration raise KeyError
else:
return self._nodes[idx] return self._nodes[idx]
def Count(self): def Count(self):

File diff suppressed because it is too large Load Diff

View File

@ -85,7 +85,9 @@ PyObject *py_appcall(
// Set exception message // Set exception message
if ( !ok ) if ( !ok )
{ {
PyErr_SetString(PyExc_ValueError, "PyAppCall: Failed to convert Python values to IDC values"); PyErr_SetString(
PyExc_ValueError,
"PyAppCall: Failed to convert Python values to IDC values");
return NULL; return NULL;
} }
@ -93,6 +95,7 @@ PyObject *py_appcall(
{ {
msg("input variables:\n" msg("input variables:\n"
"----------------\n"); "----------------\n");
qstring s; qstring s;
for ( Py_ssize_t i=0; i<nargs; i++ ) for ( Py_ssize_t i=0; i<nargs; i++ )
{ {
@ -101,6 +104,7 @@ PyObject *py_appcall(
s.qclear(); s.qclear();
} }
} }
// Do Appcall // Do Appcall
idc_value_t idc_result; idc_value_t idc_result;
error_t ret = appcall( error_t ret = appcall(
@ -146,6 +150,7 @@ PyObject *py_appcall(
s.qclear(); s.qclear();
} }
} }
// Convert IDC values back to Python values // Convert IDC values back to Python values
for ( Py_ssize_t i=0; i<nargs; i++ ) for ( Py_ssize_t i=0; i<nargs; i++ )
{ {
@ -268,6 +273,7 @@ static PyObject *dbg_get_thread_sreg_base(PyObject *py_tid, PyObject *py_sreg_va
int sreg_value = PyInt_AsLong(py_sreg_value); int sreg_value = PyInt_AsLong(py_sreg_value);
if ( dbg->thread_get_sreg_base(tid, sreg_value, &answer) != 1 ) if ( dbg->thread_get_sreg_base(tid, sreg_value, &answer) != 1 )
Py_RETURN_NONE; Py_RETURN_NONE;
return Py_BuildValue(PY_FMT64, pyul_t(answer)); return Py_BuildValue(PY_FMT64, pyul_t(answer));
} }
@ -620,6 +626,7 @@ class Appcall_callable__(object):
fields = property(__get_fields) fields = property(__get_fields)
"""Returns the field names""" """Returns the field names"""
def retrieve(self, src=None, flags=0): def retrieve(self, src=None, flags=0):
""" """
Unpacks a typed object from the database if an ea is given or from a string if a string was passed Unpacks a typed object from the database if an ea is given or from a string if a string was passed
@ -628,7 +635,7 @@ class Appcall_callable__(object):
""" """
# Nothing passed? Take the address and unpack from the database # Nothing passed? Take the address and unpack from the database
if not src: if src is None:
src = self.ea src = self.ea
if type(src) == types.StringType: if type(src) == types.StringType:
@ -740,11 +747,11 @@ class Appcall__(object):
# resolve and raise exception on error # resolve and raise exception on error
ea = Appcall__.__name_or_ea(name_or_ea) ea = Appcall__.__name_or_ea(name_or_ea)
# parse the type # parse the type
if not flags: if flags is None:
flags = 1 | 2 | 4 # PT_SIL | PT_NDC | PT_TYP flags = 1 | 2 | 4 # PT_SIL | PT_NDC | PT_TYP
result = _idaapi.idc_parse_decl(_idaapi.cvar.idati, prototype, flags) result = _idaapi.idc_parse_decl(_idaapi.cvar.idati, prototype, flags)
if not result: if result is None:
raise ValueError, "Could not parse type: " + prototype raise ValueError, "Could not parse type: " + prototype
# Return the callable method with type info # Return the callable method with type info
@ -797,7 +804,7 @@ class Appcall__(object):
Creates a string buffer. The returned value (r) will be a byref object. Creates a string buffer. The returned value (r) will be a byref object.
Use r.value to get the contents and r.size to get the buffer's size Use r.value to get the contents and r.size to get the buffer's size
""" """
if not str: if str is None:
str = "" str = ""
left = size - len(str) left = size - len(str)
if left > 0: if left > 0:
@ -834,7 +841,7 @@ class Appcall__(object):
""" """
# parse the type # parse the type
result = _idaapi.idc_parse_decl(_idaapi.cvar.idati, typestr, 1 | 2 | 4) # PT_SIL | PT_NDC | PT_TYP result = _idaapi.idc_parse_decl(_idaapi.cvar.idati, typestr, 1 | 2 | 4) # PT_SIL | PT_NDC | PT_TYP
if not result: if result is None:
raise ValueError, "Could not parse type: " + typestr raise ValueError, "Could not parse type: " + typestr
# Return the callable method with type info # Return the callable method with type info
return Appcall_callable__(ea, result[1], result[2]) return Appcall_callable__(ea, result[1], result[2])

View File

@ -42,72 +42,6 @@
%feature("director") IDB_Hooks; %feature("director") IDB_Hooks;
%feature("director") IDP_Hooks; %feature("director") IDP_Hooks;
%inline %{ %inline %{
int idaapi IDB_Callback(void *ud, int notification_code, va_list va);
class IDB_Hooks
{
public:
virtual ~IDB_Hooks() {};
bool hook() { return hook_to_notification_point(HT_IDB, IDB_Callback, this); }
bool unhook() { return unhook_from_notification_point(HT_IDB, IDB_Callback, this); }
/* Hook functions to override in Python */
virtual int byte_patched(ea_t ea) { return 0; };
virtual int cmt_changed(ea_t, bool repeatable_cmt) { return 0; };
virtual int ti_changed(ea_t ea, const type_t *type, const p_list *fnames) { msg("ti_changed hook not supported yet\n"); return 0; };
virtual int op_ti_changed(ea_t ea, int n, const type_t *type, const p_list *fnames) { msg("op_ti_changed hook not supported yet\n"); return 0; };
virtual int op_type_changed(ea_t ea, int n) { return 0; };
virtual int enum_created(enum_t id) { return 0; };
virtual int enum_deleted(enum_t id) { return 0; };
virtual int enum_bf_changed(enum_t id) { return 0; };
virtual int enum_renamed(enum_t id) { return 0; };
virtual int enum_cmt_changed(enum_t id) { return 0; };
virtual int enum_member_created(enum_t id, const_t cid) { return 0; };
virtual int enum_member_deleted(enum_t id, const_t cid) { return 0; };
virtual int struc_created(tid_t struc_id) { return 0; };
virtual int struc_deleted(tid_t struc_id) { return 0; };
virtual int struc_renamed(struc_t *sptr) { return 0; };
virtual int struc_expanded(struc_t *sptr) { return 0; };
virtual int struc_cmt_changed(tid_t struc_id) { return 0; };
virtual int struc_member_created(struc_t *sptr, member_t *mptr) { return 0; };
virtual int struc_member_deleted(struc_t *sptr, tid_t member_id) { return 0; };
virtual int struc_member_renamed(struc_t *sptr, member_t *mptr) { return 0; };
virtual int struc_member_changed(struc_t *sptr, member_t *mptr) { return 0; };
virtual int thunk_func_created(func_t *pfn) { return 0; };
virtual int func_tail_appended(func_t *pfn, func_t *tail) { return 0; };
virtual int func_tail_removed(func_t *pfn, ea_t tail_ea) { return 0; };
virtual int tail_owner_changed(func_t *tail, ea_t owner_func) { return 0; };
virtual int func_noret_changed(func_t *pfn) { return 0; };
virtual int segm_added(segment_t *s) { return 0; };
virtual int segm_deleted(ea_t startEA) { return 0; };
virtual int segm_start_changed(segment_t *s) { return 0; };
virtual int segm_end_changed(segment_t *s) { return 0; };
virtual int segm_moved(ea_t from, ea_t to, asize_t size) { return 0; };
};
// Assemble an instruction into the database (display a warning if an error is found)
// args:
// ea_t ea - linear address of instruction
// ea_t cs - cs of instruction
// ea_t ip - ip of instruction
// bool use32 - is 32bit segment?
// const char *line - line to assemble
// returns: 1: success, 0: failure
inline const int assemble(ea_t ea, ea_t cs, ea_t ip, bool use32, const char *line)
{
int inslen;
char buf[MAXSTR];
if (ph.notify != NULL)
{
inslen = ph.notify(ph.assemble, ea, cs, ip, use32, line, buf);
if (inslen > 0)
{
patch_many_bytes(ea, buf, inslen);
return 1;
}
}
return 0;
}
//<inline(py_idp)> //<inline(py_idp)>
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -117,7 +51,7 @@ inline const int assemble(ea_t ea, ea_t cs, ea_t ip, bool use32, const char *lin
#<pydoc> #<pydoc>
def AssembleLine(ea, cs, ip, use32, line): def AssembleLine(ea, cs, ip, use32, line):
""" """
Assemble an instruction to a buffer (display a warning if an error is found) Assemble an instruction to a string (display a warning if an error is found)
@param ea: linear address of instruction @param ea: linear address of instruction
@param cs: cs of instruction @param cs: cs of instruction
@ -143,6 +77,39 @@ static PyObject *AssembleLine(ea_t ea, ea_t cs, ea_t ip, bool use32, const char
Py_RETURN_NONE; Py_RETURN_NONE;
} }
//---------------------------------------------------------------------------
/*
#<pydoc>
def assemble(ea, cs, ip, use32, line):
"""
Assemble an instruction into the database (display a warning if an error is found)
@param ea: linear address of instruction
@param cs: cs of instruction
@param ip: ip of instruction
@param use32: is 32bit segment?
@param line: line to assemble
@return: Boolean. True on success.
"""
#</pydoc>
*/
bool assemble(ea_t ea, ea_t cs, ea_t ip, bool use32, const char *line)
{
int inslen;
char buf[MAXSTR];
if (ph.notify != NULL)
{
inslen = ph.notify(ph.assemble, ea, cs, ip, use32, line, buf);
if (inslen > 0)
{
patch_many_bytes(ea, buf, inslen);
return true;
}
}
return false;
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
/* /*
#<pydoc> #<pydoc>
@ -408,6 +375,7 @@ static PyObject *ph_get_regnames()
PyObject *py_result = PyList_New(ph.regsNum); PyObject *py_result = PyList_New(ph.regsNum);
for ( Py_ssize_t i=0; i<ph.regsNum; i++ ) for ( Py_ssize_t i=0; i<ph.regsNum; i++ )
PyList_SetItem(py_result, i, PyString_FromString(ph.regNames[i])); PyList_SetItem(py_result, i, PyString_FromString(ph.regNames[i]));
return py_result; return py_result;
} }
@ -415,6 +383,21 @@ static PyObject *ph_get_regnames()
/* /*
#<pydoc> #<pydoc>
class IDP_Hooks(object): class IDP_Hooks(object):
def hook(self):
"""
Creates an IDP hook
@return: Boolean true on success
"""
pass
def unhook(self):
"""
Removes the IDP hook
@return: Boolean true on success
"""
pass
def custom_ana(self): def custom_ana(self):
""" """
Analyzes and decodes an instruction at idaapi.cmd.ea Analyzes and decodes an instruction at idaapi.cmd.ea
@ -480,9 +463,9 @@ class IDP_Hooks(object):
""" """
pass pass
def is_sane_insn(self, no_crefs): def may_be_func(self, no_crefs):
""" """
can a function start here? Can a function start here?
@param state: autoanalysis phase @param state: autoanalysis phase
0: creating functions 0: creating functions
1: creating chunks 1: creating chunks
@ -490,8 +473,124 @@ class IDP_Hooks(object):
@return: integer (probability 0..100) @return: integer (probability 0..100)
""" """
pass pass
def closebase(self):
"""
The database will be closed now
"""
pass
def savebase(self):
"""
The database is being saved. Processor module should
"""
pass
def rename(self, ea, new_name):
"""
The kernel is going to rename a byte.
@param ea: Address
@param new_name: The new name
@return:
- If returns value <=0, then the kernel should
not rename it. See also the 'renamed' event
"""
def renamed(self, ea, new_name, local_name):
"""
The kernel has renamed a byte
@param ea: Address
@param new_name: The new name
@param local_name: Is local name
@return: Ignored
"""
def undefine(self, ea):
"""
An item in the database (insn or data) is being deleted
@param ea: Address
@return:
- returns: >0-ok, <=0-the kernel should stop
- if the return value is positive:
bit0 - ignored
bit1 - do not delete srareas at the item end
"""
def make_code(self, ea, size):
"""
An instruction is being created
@param ea: Address
@param size: Instruction size
@return: 1-ok, <=0-the kernel should stop
"""
def make_code(self, ea, size):
"""
An instruction is being created
@param ea: Address
@param size: Instruction size
@return: 1-ok, <=0-the kernel should stop
"""
def make_data(self, ea, flags, tid, len):
"""
A data item is being created
@param ea: Address
@param tid: type id
@param flags: item flags
@param len: data item size
@return: 1-ok, <=0-the kernel should stop
"""
def load_idasgn(self, short_sig_name):
"""
FLIRT signature have been loaded for normal processing
(not for recognition of startup sequences)
@param short_sig_name: signature name
@return: Ignored
"""
def add_func(self, func):
"""
The kernel has added a function
@param func: the func_t instance
@return: Ignored
"""
def del_func(self, func):
"""
The kernel is about to delete a function
@param func: the func_t instance
@return: 1-ok,<=0-do not delete
"""
def is_call_insn(self, ea, func_name):
"""
Is the instruction a "call"?
@param ea: instruction address
@return: 1-unknown, 0-no, 2-yes
"""
def is_ret_insn(self, ea, func_name):
"""
Is the instruction a "return"?
@param ea: instruction address
@param strict: - True: report only ret instructions
False: include instructions like "leave" which begins the function epilog
@return: 1-unknown, 0-no, 2-yes
"""
#</pydoc> #</pydoc>
*/ */
//---------------------------------------------------------------------------
// IDP hooks
//---------------------------------------------------------------------------
int idaapi IDP_Callback(void *ud, int notification_code, va_list va); int idaapi IDP_Callback(void *ud, int notification_code, va_list va);
class IDP_Hooks class IDP_Hooks
{ {
@ -544,12 +643,287 @@ public:
{ {
return 0; return 0;
} }
virtual int closebase()
{
return 0;
}
virtual void savebase()
{
}
virtual int rename(ea_t ea, const char *new_name)
{
return 0;
}
virtual void renamed(ea_t ea, const char *new_name, bool local_name)
{
}
virtual int undefine(ea_t ea)
{
return 0;
}
virtual int make_code(ea_t ea, asize_t size)
{
return 0;
}
virtual int make_data(ea_t ea, flags_t flags, tid_t tid, asize_t len)
{
return 0;
}
virtual void load_idasgn(const char *short_sig_name)
{
}
virtual void add_func(func_t *func)
{
}
virtual int del_func(func_t *func)
{
return 0;
}
virtual int is_call_insn(ea_t ea)
{
return 0;
}
virtual int is_ret_insn(ea_t ea, bool strict)
{
return 0;
}
};
//---------------------------------------------------------------------------
// IDB hooks
//---------------------------------------------------------------------------
int idaapi IDB_Callback(void *ud, int notification_code, va_list va);
class IDB_Hooks
{
public:
virtual ~IDB_Hooks() {};
bool hook()
{
return hook_to_notification_point(HT_IDB, IDB_Callback, this);
}
bool unhook()
{
return unhook_from_notification_point(HT_IDB, IDB_Callback, this);
}
// Hook functions to override in Python
virtual int byte_patched(ea_t ea) { return 0; };
virtual int cmt_changed(ea_t, bool repeatable_cmt) { return 0; };
virtual int ti_changed(ea_t ea, const type_t *type, const p_list *fnames) { msg("ti_changed hook not supported yet\n"); return 0; };
virtual int op_ti_changed(ea_t ea, int n, const type_t *type, const p_list *fnames) { msg("op_ti_changed hook not supported yet\n"); return 0; };
virtual int op_type_changed(ea_t ea, int n) { return 0; };
virtual int enum_created(enum_t id) { return 0; };
virtual int enum_deleted(enum_t id) { return 0; };
virtual int enum_bf_changed(enum_t id) { return 0; };
virtual int enum_renamed(enum_t id) { return 0; };
virtual int enum_cmt_changed(enum_t id) { return 0; };
virtual int enum_member_created(enum_t id, const_t cid) { return 0; };
virtual int enum_member_deleted(enum_t id, const_t cid) { return 0; };
virtual int struc_created(tid_t struc_id) { return 0; };
virtual int struc_deleted(tid_t struc_id) { return 0; };
virtual int struc_renamed(struc_t *sptr) { return 0; };
virtual int struc_expanded(struc_t *sptr) { return 0; };
virtual int struc_cmt_changed(tid_t struc_id) { return 0; };
virtual int struc_member_created(struc_t *sptr, member_t *mptr) { return 0; };
virtual int struc_member_deleted(struc_t *sptr, tid_t member_id) { return 0; };
virtual int struc_member_renamed(struc_t *sptr, member_t *mptr) { return 0; };
virtual int struc_member_changed(struc_t *sptr, member_t *mptr) { return 0; };
virtual int thunk_func_created(func_t *pfn) { return 0; };
virtual int func_tail_appended(func_t *pfn, func_t *tail) { return 0; };
virtual int func_tail_removed(func_t *pfn, ea_t tail_ea) { return 0; };
virtual int tail_owner_changed(func_t *tail, ea_t owner_func) { return 0; };
virtual int func_noret_changed(func_t *pfn) { return 0; };
virtual int segm_added(segment_t *s) { return 0; };
virtual int segm_deleted(ea_t startEA) { return 0; };
virtual int segm_start_changed(segment_t *s) { return 0; };
virtual int segm_end_changed(segment_t *s) { return 0; };
virtual int segm_moved(ea_t from, ea_t to, asize_t size) { return 0; };
}; };
//</inline(py_idp)> //</inline(py_idp)>
%} %}
%{ %{
//<code(py_idp)>
//-------------------------------------------------------------------------
int idaapi IDP_Callback(void *ud, int notification_code, va_list va)
{
IDP_Hooks *proxy = (IDP_Hooks *)ud;
int ret = 0;
try
{
switch ( notification_code )
{
case processor_t::custom_ana:
ret = proxy->custom_ana() ? 1 + cmd.size : 0;
break;
case processor_t::custom_out:
ret = proxy->custom_out() ? 2 : 0;
break;
case processor_t::custom_emu:
ret = proxy->custom_emu() ? 2 : 0;
break;
case processor_t::custom_outop:
{
op_t *op = va_arg(va, op_t *);
PyObject *py_obj = create_idaapi_linked_class_instance(S_PY_OP_T_CLSNAME, op);
if ( py_obj == NULL )
break;
ret = proxy->custom_outop(py_obj) ? 2 : 0;
Py_XDECREF(py_obj);
break;
}
case processor_t::custom_mnem:
{
PyObject *py_ret = proxy->custom_mnem();
if ( py_ret != NULL && PyString_Check(py_ret) )
{
char *outbuffer = va_arg(va, char *);
size_t bufsize = va_arg(va, size_t);
qstrncpy(outbuffer, PyString_AS_STRING(py_ret), bufsize);
ret = 2;
}
else
{
ret = 0;
}
Py_XDECREF(py_ret);
break;
}
case processor_t::is_sane_insn:
{
int no_crefs = va_arg(va, int);
ret = proxy->is_sane_insn(no_crefs);
break;
}
case processor_t::may_be_func:
{
int state = va_arg(va, int);
ret = proxy->may_be_func(state);
break;
}
case processor_t::closebase:
{
proxy->closebase();
break;
}
case processor_t::savebase:
{
proxy->savebase();
break;
}
case processor_t::rename:
{
ea_t ea = va_arg(va, ea_t);
const char *new_name = va_arg(va, const char *);
ret = proxy->rename(ea, new_name);
break;
}
case processor_t::renamed:
{
ea_t ea = va_arg(va, ea_t);
const char *new_name = va_arg(va, const char *);
bool local_name = va_argi(va, bool);
proxy->renamed(ea, new_name, local_name);
break;
}
case processor_t::undefine:
{
ea_t ea = va_arg(va, ea_t);
ret = proxy->undefine(ea);
break;
}
case processor_t::make_code:
{
ea_t ea = va_arg(va, ea_t);
asize_t size = va_arg(va, asize_t);
ret = proxy->make_code(ea, size);
break;
}
case processor_t::make_data:
{
ea_t ea = va_arg(va, ea_t);
flags_t flags = va_arg(va, flags_t);
tid_t tid = va_arg(va, tid_t);
asize_t len = va_arg(va, asize_t);
ret = proxy->make_data(ea, flags, tid, len);
break;
}
case processor_t::load_idasgn:
{
const char *short_sig_name = va_arg(va, const char *);
proxy->load_idasgn(short_sig_name);
break;
}
case processor_t::add_func:
{
func_t *func = va_arg(va, func_t *);
proxy->add_func(func);
break;
}
case processor_t::del_func:
{
func_t *func = va_arg(va, func_t *);
ret = proxy->del_func(func);
break;
}
case processor_t::is_call_insn:
{
ea_t ea = va_arg(va, ea_t);
ret = proxy->is_call_insn(ea);
break;
}
case processor_t::is_ret_insn:
{
ea_t ea = va_arg(va, ea_t);
bool strict = va_argi(va, bool);
ret = proxy->is_ret_insn(ea, strict);
break;
}
}
}
catch (Swig::DirectorException &)
{
msg("Exception in IDP Hook function:\n");
if ( PyErr_Occurred() )
PyErr_Print();
}
return ret;
}
//---------------------------------------------------------------------------
int idaapi IDB_Callback(void *ud, int notification_code, va_list va) int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
{ {
class IDB_Hooks *proxy = (class IDB_Hooks *)ud; class IDB_Hooks *proxy = (class IDB_Hooks *)ud;
@ -615,12 +989,20 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
id = va_arg(va, enum_t); id = va_arg(va, enum_t);
return proxy->enum_cmt_changed(id); return proxy->enum_cmt_changed(id);
#ifdef NO_OBSOLETE_FUNCS
case idb_event::enum_member_created: case idb_event::enum_member_created:
#else
case idb_event::enum_const_created:
#endif
id = va_arg(va, enum_t); id = va_arg(va, enum_t);
cid = va_arg(va, const_t); cid = va_arg(va, const_t);
return proxy->enum_member_created(id, cid); return proxy->enum_member_created(id, cid);
#ifdef NO_OBSOLETE_FUNCS
case idb_event::enum_member_deleted: case idb_event::enum_member_deleted:
#else
case idb_event::enum_const_deleted:
#endif
id = va_arg(va, enum_t); id = va_arg(va, enum_t);
cid = va_arg(va, const_t); cid = va_arg(va, const_t);
return proxy->enum_member_deleted(id, cid); return proxy->enum_member_deleted(id, cid);
@ -722,86 +1104,6 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
return 0; return 0;
} }
//<code(py_idp)>
//-------------------------------------------------------------------------
int idaapi IDP_Callback(void *ud, int notification_code, va_list va)
{
IDP_Hooks *proxy = (IDP_Hooks *)ud;
int ret;
try
{
switch ( notification_code )
{
default:
ret = 0;
break;
case processor_t::custom_ana:
ret = proxy->custom_ana() ? 1 + cmd.size : 0;
break;
case processor_t::custom_out:
ret = proxy->custom_out() ? 2 : 0;
break;
case processor_t::custom_emu:
ret = proxy->custom_emu() ? 2 : 0;
break;
case processor_t::custom_outop:
{
op_t *op = va_arg(va, op_t *);
PyObject *py_obj = create_idaapi_linked_class_instance(S_PY_OP_T_CLSNAME, op);
if ( py_obj == NULL )
break;
ret = proxy->custom_outop(py_obj) ? 2 : 0;
Py_XDECREF(py_obj);
break;
}
case processor_t::custom_mnem:
{
PyObject *py_ret = proxy->custom_mnem();
if ( py_ret != NULL && PyString_Check(py_ret) )
{
char *outbuffer = va_arg(va, char *);
size_t bufsize = va_arg(va, size_t);
qstrncpy(outbuffer, PyString_AS_STRING(py_ret), bufsize);
ret = 2;
}
else
{
ret = 0;
}
Py_XDECREF(py_ret);
break;
}
case processor_t::is_sane_insn:
{
int no_crefs = va_arg(va, int);
ret = proxy->is_sane_insn(no_crefs);
break;
}
case processor_t::may_be_func:
{
int state = va_arg(va, int);
ret = proxy->may_be_func(state);
break;
}
}
}
catch (Swig::DirectorException &)
{
msg("Exception in IDP Hook function:\n");
if ( PyErr_Occurred() )
PyErr_Print();
}
return ret;
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
//</code(py_idp)> //</code(py_idp)>
%} %}

File diff suppressed because it is too large Load Diff

View File

@ -78,7 +78,6 @@
//<code(py_lines)> //<code(py_lines)>
//------------------------------------------------------------------------ //------------------------------------------------------------------------
static PyObject *py_get_user_defined_prefix = NULL; static PyObject *py_get_user_defined_prefix = NULL;
static qstring py_get_user_defined_prefix_err;
static void idaapi s_py_get_user_defined_prefix( static void idaapi s_py_get_user_defined_prefix(
ea_t ea, ea_t ea,
int lnnum, int lnnum,
@ -92,12 +91,9 @@ static void idaapi s_py_get_user_defined_prefix(
PY_FMT64 "iis" PY_FMT64, PY_FMT64 "iis" PY_FMT64,
ea, lnnum, indent, line, bufsize); ea, lnnum, indent, line, bufsize);
if ( PyW_GetError(&py_get_user_defined_prefix_err) || py_ret == NULL ) // Error? Display it
{ // No error? Copy the buffer
msg("py_get_user_defined_prefix() error: %s\n", py_get_user_defined_prefix_err.c_str()); if ( !PyW_ShowCbErr("py_get_user_defined_prefix") )
PyErr_Clear();
}
else
{ {
Py_ssize_t py_len; Py_ssize_t py_len;
char *py_str; char *py_str;
@ -192,6 +188,7 @@ PyObject *py_tag_remove(const char *instr)
char *buf = new char[sz + 5]; char *buf = new char[sz + 5];
if ( buf == NULL ) if ( buf == NULL )
Py_RETURN_NONE; Py_RETURN_NONE;
ssize_t r = tag_remove(instr, buf, sz); ssize_t r = tag_remove(instr, buf, sz);
PyObject *res; PyObject *res;
if ( r < 0 ) if ( r < 0 )

View File

@ -12,6 +12,7 @@
// TODO: These could be wrapped if needed // TODO: These could be wrapped if needed
%ignore load_info_t; %ignore load_info_t;
%ignore add_plugin_option; %ignore add_plugin_option;
%ignore get_plugins_path;
%ignore build_loaders_list; %ignore build_loaders_list;
%ignore free_loaders_list; %ignore free_loaders_list;
%ignore get_loader_name_from_dll; %ignore get_loader_name_from_dll;
@ -147,6 +148,7 @@ static int py_mem2base(PyObject *py_mem, ea_t ea, long fpos = -1)
char *buf; char *buf;
if ( PyString_AsStringAndSize(py_mem, &buf, &len) == -1 ) if ( PyString_AsStringAndSize(py_mem, &buf, &len) == -1 )
return 0; return 0;
return mem2base((void *)buf, ea, ea+len, fpos); return mem2base((void *)buf, ea, ea+len, fpos);
} }
@ -168,6 +170,7 @@ static PyObject *py_load_plugin(const char *name)
plugin_t *r = load_plugin(name); plugin_t *r = load_plugin(name);
if ( r == NULL ) if ( r == NULL )
Py_RETURN_NONE; Py_RETURN_NONE;
return PyCObject_FromVoidPtr(r, NULL); return PyCObject_FromVoidPtr(r, NULL);
} }
@ -187,6 +190,7 @@ static bool py_run_plugin(PyObject *plg, int arg)
{ {
if ( !PyCObject_Check(plg) ) if ( !PyCObject_Check(plg) )
return false; return false;
return run_plugin((plugin_t *)PyCObject_AsVoidPtr(plg), arg); return run_plugin((plugin_t *)PyCObject_AsVoidPtr(plg), arg);
} }

View File

@ -25,7 +25,11 @@ static int idaapi py_import_enum_cb(
uval_t ord, uval_t ord,
void *param) void *param)
{ {
PyObject *py_ea = Py_BuildValue(PY_FMT64, pyul_t(ea)); // If no name, try to get the name associated with the 'ea'. It may be coming from IDS
char name_buf[MAXSTR];
if ( name == NULL )
name = get_true_name(BADADDR, ea, name_buf, sizeof(name_buf));
PyObject *py_name; PyObject *py_name;
if ( name == NULL ) if ( name == NULL )
{ {
@ -36,13 +40,25 @@ static int idaapi py_import_enum_cb(
{ {
py_name = PyString_FromString(name); py_name = PyString_FromString(name);
} }
PyObject *py_ord = Py_BuildValue(PY_FMT64, pyul_t(ord)); PyObject *py_ord = Py_BuildValue(PY_FMT64, pyul_t(ord));
PyObject *py_result = PyObject_CallFunctionObjArgs((PyObject *)param, py_ea, py_name, py_ord, NULL); PyObject *py_ea = Py_BuildValue(PY_FMT64, pyul_t(ea));
PYW_GIL_ENSURE;
PyObject *py_result = PyObject_CallFunctionObjArgs(
(PyObject *)param,
py_ea,
py_name,
py_ord,
NULL);
PYW_GIL_RELEASE;
int r = py_result != NULL && PyObject_IsTrue(py_result) ? 1 : 0; int r = py_result != NULL && PyObject_IsTrue(py_result) ? 1 : 0;
Py_DECREF(py_ea); Py_DECREF(py_ea);
Py_DECREF(py_name); Py_DECREF(py_name);
Py_DECREF(py_ord); Py_DECREF(py_ord);
Py_XDECREF(py_result); Py_XDECREF(py_result);
return r; return r;
} }
@ -90,6 +106,7 @@ static PyObject *py_get_import_module_name(int mod_index)
char buf[MAXSTR]; char buf[MAXSTR];
if ( !get_import_module_name(mod_index, buf, sizeof(buf)) ) if ( !get_import_module_name(mod_index, buf, sizeof(buf)) )
Py_RETURN_NONE; Py_RETURN_NONE;
return PyString_FromString(buf); return PyString_FromString(buf);
} }
@ -234,6 +251,7 @@ static int py_enum_import_names(int mod_index, PyObject *py_cb)
{ {
if ( !PyCallable_Check(py_cb) ) if ( !PyCallable_Check(py_cb) )
return -1; return -1;
return enum_import_names(mod_index, py_import_enum_cb, py_cb); return enum_import_names(mod_index, py_import_enum_cb, py_cb);
} }
@ -244,6 +262,7 @@ static PyObject *switch_info_ex_t_create()
return PyCObject_FromVoidPtr(inst, NULL); return PyCObject_FromVoidPtr(inst, NULL);
} }
//---------------------------------------------------------------------------
static bool switch_info_ex_t_destroy(PyObject *py_obj) static bool switch_info_ex_t_destroy(PyObject *py_obj)
{ {
if ( !PyCObject_Check(py_obj) ) if ( !PyCObject_Check(py_obj) )

View File

@ -45,7 +45,7 @@ PyObject *py_get_debug_names(ea_t ea1, ea_t ea2)
for (ea_name_vec_t::iterator it=names.begin();it!=names.end();++it) for (ea_name_vec_t::iterator it=names.begin();it!=names.end();++it)
{ {
PyDict_SetItem(dict, PyDict_SetItem(dict,
PyInt_FromSize_t(it->ea), Py_BuildValue(PY_FMT64, it->ea),
PyString_FromString(it->name.c_str())); PyString_FromString(it->name.c_str()));
} }
return dict; return dict;
@ -63,12 +63,14 @@ class NearestName:
def __init__(self, ea_names): def __init__(self, ea_names):
self.update(ea_names) self.update(ea_names)
def update(self, ea_names): def update(self, ea_names):
"""Updates the ea/names map""" """Updates the ea/names map"""
self._names = ea_names self._names = ea_names
self._addrs = ea_names.keys() self._addrs = ea_names.keys()
self._addrs.sort() self._addrs.sort()
def find(self, ea): def find(self, ea):
""" """
Returns a tupple (ea, name, pos) that is the nearest to the passed ea Returns a tupple (ea, name, pos) that is the nearest to the passed ea
@ -85,13 +87,21 @@ class NearestName:
return None return None
return self[pos] return self[pos]
def _get_item(self, index):
ea = self._addrs[index]
return (ea, self._names[ea], index)
def __iter__(self):
return (self._get_item(index) for index in xrange(0, len(self._addrs)))
def __getitem__(self, index): def __getitem__(self, index):
"""Returns the tupple (ea, name, index)""" """Returns the tupple (ea, name, index)"""
if index > len(self._addrs): if index > len(self._addrs):
raise StopIteration raise StopIteration
ea = self._addrs[index] return self._get_item(index)
return (ea, self._names[ea], index)
%} %}
%include "name.hpp" %include "name.hpp"

View File

@ -89,3 +89,11 @@
%rename (hashset_idx) netnode::hashset(const char *idx, nodeidx_t value, char tag=htag); %rename (hashset_idx) netnode::hashset(const char *idx, nodeidx_t value, char tag=htag);
%include "netnode.hpp" %include "netnode.hpp"
%extend netnode
{
nodeidx_t index()
{
return self->operator nodeidx_t();
}
}

View File

@ -23,7 +23,14 @@
%ignore qthread_join; %ignore qthread_join;
%ignore qthread_kill; %ignore qthread_kill;
%ignore qthread_self; %ignore qthread_self;
%ignore qthread_same;
%ignore qthread_t; %ignore qthread_t;
%ignore qhandle_t;
%ignore qpipe_create;
%ignore qpipe_read;
%ignore qpipe_write;
%ignore qpipe_close;
%ignore qwait_for_handles;
%ignore qstrlen; %ignore qstrlen;
%ignore qstrcmp; %ignore qstrcmp;
%ignore qstrstr; %ignore qstrstr;
@ -65,8 +72,11 @@
%ignore swap_value; %ignore swap_value;
%ignore qalloc_or_throw; %ignore qalloc_or_throw;
%ignore qrealloc_or_throw; %ignore qrealloc_or_throw;
%ignore launch_process_t; %ignore get_buffer_for_sysdir;
%ignore init_process; %ignore get_buffer_for_winerr;
%ignore call_atexits;
%ignore launch_process_params_t;
%ignore launch_process;
%ignore term_process; %ignore term_process;
%ignore get_process_exit_code; %ignore get_process_exit_code;
%ignore BELOW_NORMAL_PRIORITY_CLASS; %ignore BELOW_NORMAL_PRIORITY_CLASS;

View File

@ -148,8 +148,20 @@
// Check that the argument is a callable Python object // Check that the argument is a callable Python object
%typemap(in) PyObject *pyfunc { %typemap(in) PyObject *pyfunc {
if (!PyCallable_Check($input)) { if (!PyCallable_Check($input)) {
PyErr_SetString(PyExc_TypeError, "Expecting a callable object"); PyErr_SetString(PyExc_TypeError, "Expected a callable object");
return NULL; return NULL;
} }
$1 = $input; $1 = $input;
} }
// Convert ea_t
%typemap(in) ea_t
{
uint64 $1_temp;
if ( !PyW_GetNumber($input, &$1_temp) )
{
PyErr_SetString(PyExc_TypeError, "Expected an ea_t type");
return NULL;
}
$1 = ea_t($1_temp);
}

View File

@ -62,6 +62,9 @@
%ignore print_type; %ignore print_type;
%ignore show_type; %ignore show_type;
%ignore show_plist; %ignore show_plist;
%ignore skip_function_arg_names;
%ignore perform_funcarg_conversion;
%ignore get_argloc_info;
%ignore extract_pstr; %ignore extract_pstr;
%ignore extract_name; %ignore extract_name;
@ -167,6 +170,7 @@ PyObject *idc_parse_decl(til_t *ti, const char *decl, int flags)
bool ok = parse_decl(ti, decl, &name, &type, &fields, flags); bool ok = parse_decl(ti, decl, &name, &type, &fields, flags);
if ( !ok ) if ( !ok )
Py_RETURN_NONE; Py_RETURN_NONE;
return Py_BuildValue("(sss)", return Py_BuildValue("(sss)",
name.c_str(), name.c_str(),
(char *)type.c_str(), (char *)type.c_str(),
@ -256,7 +260,14 @@ PyObject *py_unpack_object_from_idb(
type_t *type = (type_t *) PyString_AsString(py_type); type_t *type = (type_t *) PyString_AsString(py_type);
p_list *fields = (p_list *) PyString_AsString(py_fields); p_list *fields = (p_list *) PyString_AsString(py_fields);
idc_value_t idc_obj; idc_value_t idc_obj;
error_t err = unpack_object_from_idb(&idc_obj, ti, type, fields, ea, NULL, pio_flags); error_t err = unpack_object_from_idb(
&idc_obj,
ti,
type,
fields,
ea,
NULL,
pio_flags);
// Unpacking failed? // Unpacking failed?
if ( err != eOk ) if ( err != eOk )
@ -265,9 +276,11 @@ PyObject *py_unpack_object_from_idb(
// Convert // Convert
PyObject *py_ret(NULL); PyObject *py_ret(NULL);
err = idcvar_to_pyvar(idc_obj, &py_ret); err = idcvar_to_pyvar(idc_obj, &py_ret);
// Conversion failed? // Conversion failed?
if ( err != CIP_OK ) if ( err != CIP_OK )
return Py_BuildValue("(ii)", 0, err); return Py_BuildValue("(ii)", 0, err);
PyObject *py_result = Py_BuildValue("(iO)", 1, py_ret); PyObject *py_result = Py_BuildValue("(iO)", 1, py_ret);
Py_DECREF(py_ret); Py_DECREF(py_ret);
return py_result; return py_result;
@ -315,7 +328,13 @@ PyObject *py_unpack_object_from_bv(
memcpy(bytes.begin(), PyString_AsString(py_bytes), bytes.size()); memcpy(bytes.begin(), PyString_AsString(py_bytes), bytes.size());
idc_value_t idc_obj; idc_value_t idc_obj;
error_t err = unpack_object_from_bv(&idc_obj, ti, type, fields, bytes, pio_flags); error_t err = unpack_object_from_bv(
&idc_obj,
ti,
type,
fields,
bytes,
pio_flags);
// Unpacking failed? // Unpacking failed?
if ( err != eOk ) if ( err != eOk )
@ -324,9 +343,11 @@ PyObject *py_unpack_object_from_bv(
// Convert // Convert
PyObject *py_ret(NULL); PyObject *py_ret(NULL);
err = idcvar_to_pyvar(idc_obj, &py_ret); err = idcvar_to_pyvar(idc_obj, &py_ret);
// Conversion failed? // Conversion failed?
if ( err != CIP_OK ) if ( err != CIP_OK )
return Py_BuildValue("(ii)", 0, err); return Py_BuildValue("(ii)", 0, err);
PyObject *py_result = Py_BuildValue("(iO)", 1, py_ret); PyObject *py_result = Py_BuildValue("(iO)", 1, py_ret);
Py_DECREF(py_ret); Py_DECREF(py_ret);
return py_result; return py_result;

View File

@ -64,6 +64,7 @@ PyObject *py_init_output_buffer(size_t size = MAXSTR)
PyObject *py_str = PyString_FromStringAndSize(NULL, size); PyObject *py_str = PyString_FromStringAndSize(NULL, size);
if ( py_str == NULL ) if ( py_str == NULL )
Py_RETURN_NONE; Py_RETURN_NONE;
init_output_buffer(PyString_AsString(py_str), size); init_output_buffer(PyString_AsString(py_str), size);
return py_str; return py_str;
} }
@ -326,6 +327,7 @@ bool py_out_name_expr(
off = adiff_t(v); off = adiff_t(v);
else else
off = BADADDR; off = BADADDR;
return op == NULL ? false : out_name_expr(*op, ea, off); return op == NULL ? false : out_name_expr(*op, ea, off);
} }
@ -449,6 +451,7 @@ static void insn_t_set_cs(PyObject *self, PyObject *value)
insn_t *link = insn_t_get_clink(self); insn_t *link = insn_t_get_clink(self);
if ( link == NULL ) if ( link == NULL )
return; return;
uint64 v(0); uint64 v(0);
PyW_GetNumber(value, &v); PyW_GetNumber(value, &v);
link->cs = ea_t(v); link->cs = ea_t(v);
@ -886,7 +889,7 @@ class op_t(py_clinked_object_t):
def is_reg(self, r): def is_reg(self, r):
"""Checks if the register operand is the given processor register""" """Checks if the register operand is the given processor register"""
return self.type == idaapi.o_reg and self == r return self.type == _idaapi.o_reg and self == r
def has_reg(self, r): def has_reg(self, r):
"""Checks if the operand accesses the given processor register""" """Checks if the operand accesses the given processor register"""
@ -1000,14 +1003,23 @@ class insn_t(py_clinked_object_t):
def _create_clink(self): def _create_clink(self):
return _idaapi.insn_t_create() return _idaapi.insn_t_create()
def _del_clink(self, lnk): def _del_clink(self, lnk):
return _idaapi.insn_t_destroy(lnk) return _idaapi.insn_t_destroy(lnk)
def __iter__(self):
return (self.Operands[idx] for idx in xrange(0, UA_MAXOP))
def __getitem__(self, idx): def __getitem__(self, idx):
""" """
Operands can be accessed directly as indexes Operands can be accessed directly as indexes
@return op_t: Returns an operand of type op_t @return op_t: Returns an operand of type op_t
""" """
if idx >= UA_MAXOP:
raise KeyError
else:
return self.Operands[idx] return self.Operands[idx]
def is_macro(self): def is_macro(self):