IDAPython 1.5.3

- IDA Pro 6.2 support
- added set_idc_func_ex(): it is now possible to add new IDC functions using Python
- added visit_patched_bytes() (see ex_patch.py)
- added support for the multiline text input control in the Form class
- added support for the editable/readonly dropdown list control in the Form class
- added execute_sync() to register a function call into the UI message queue
- added execute_ui_requests() / check ex_uirequests.py
- added add_hotkey() / del_hotkey() to bind Python methods to hotkeys
- added register_timer()/unregister_timer(). Check ex_timer.py
- added the IDC (Arrays) netnode manipulation layer into idc.py
- added idautils.Structs() and StructMembers() generator functions
- removed the "Run Python Statement" menu item. IDA now has a unified dialog. 
  Use RunPlugin("python", 0) to invoke it manually.
- better error messages for script plugins, loaders and processor modules
- bugfix: Dbg_Hooks.dbg_run_to() was receiving wrong input
- bugfix: A few Enum related functions were not properly working in idc.py
- bugfix: GetIdaDirectory() and GetProcessName() were broken in idc.py
- bugfix: idaapi.get_item_head() / idc.ItemHead() were not working
This commit is contained in:
skochinsky@gmail.com 2011-10-14 14:24:38 +00:00
parent 96cd02db6c
commit 1258fab948
36 changed files with 3455 additions and 658 deletions

View File

@ -7,7 +7,7 @@ The IDAPython Team:
* Hex-Rays - http://www.hex-rays.com/ - <support@hex-rays.com>
Hex-Rays joined the project in September 2009 and started contributing.
Hex-Rays joined the IDAPython project in September 2009 and started contributing.
It is primarily maintained by Elias Bachaalany.
@ -21,3 +21,4 @@ The IDAPython Team:
Igor Skochinsky
Sebastian Muniz
cbwhiz
Arnaud Diederen

View File

@ -1,6 +1,6 @@
----------------------------------------------------------
IDAPython - Python plugin for Interactive Disassembler Pro
----------------------------------------------------------
------------------------------------------------------
IDAPython - Python plugin for Interactive Disassembler
------------------------------------------------------
Building From Source
--------------------
@ -36,10 +36,10 @@ BUILDING
Make sure all the needed tools (compiler, swig) are on the PATH.
1. Unpack the IDAPython source and IDA Pro SDK into the following
1. Unpack the IDAPython source and IDA SDK into the following
directory structure:
swigsdk-versions/x.y/ - A supported version of the IDA Pro SDK
swigsdk-versions/x.y/ - A supported version of the IDA SDK
idapython/ - IDAPython source code
2. On Mac OS X copy libida.dylib from the IDA install directory to

View File

@ -1,12 +1,32 @@
Please see http://code.google.com/p/idapython/source/list for a detailed list of changes.
Changes from version 1.5.2 to 1.5.3
------------------------------------
- added set_idc_func_ex(): it is now possible to add new IDC functions using Python
- added visit_patched_bytes() (see ex_patch.py)
- added support for the multiline text input control in the Form class
- added support for the editable/readonly dropdown list control in the Form class
- added execute_sync() to register a function call into the UI message queue
- added execute_ui_requests() / check ex_uirequests.py
- added add_hotkey() / del_hotkey() to bind Python methods to hotkeys
- added register_timer()/unregister_timer(). Check ex_timer.py
- added the IDC (Arrays) netnode manipulation layer into idc.py
- added idautils.Structs() and StructMembers() generator functions
- removed the "Run Python Statment" menu item. IDA now has a unified dialog.
Use RunPlugin("python", 0) to invoke it manually.
- better error messages for script plugins, loaders and processor modules
- bugfix: Dbg_Hooks.dbg_run_to() was receiving wrong input
- bugfix: A few Enum related functions were not properly working in idc.py
- bugfix: GetIdaDirectory() and GetProcessName() were broken in idc.py
- bugfix: idaapi.get_item_head() / idc.ItemHead() were not working
Changes from version 1.5.1 to 1.5.2
------------------------------------
- added ui_term/ui_save/ui_saved/ui_get_ea_hint UI notifications
- added ph_get_operand_info() to retrieve operand information while debugging
- added PteDump.py script
- some code refactoring
- bugfix: read/write_dbg_memory() and dbg_get_thread_sreg_base() were not working with all debugger modules
- bugfix: idaapi.netnode.getblob() was limited to MAXSPECSIZE
- bugfix: idc.GetString()/idaapi.get_ascii_contents()/idautils.Strings() were limited to MAXSTR string length
- bugfix: idaapi.del_menu_item() was failing to delete some menu items

View File

@ -1,8 +1,8 @@
----------------------------------------------------------
IDAPython - Python plugin for Interactive Disassembler Pro
----------------------------------------------------------
------------------------------------------------------
IDAPython - Python plugin for Interactive Disassembler
------------------------------------------------------
WHAT IS IDAPTYHON?
What is IDAPython?
------------------
IDAPython is an IDA plugin which makes it possible to write scripts
@ -12,7 +12,7 @@ access to both the IDA API and any installed Python module.
Check the scripts in the examples directory to get an quick glimpse.
AVAILABILITY
Availability
------------
Latest stable versions of IDAPython are available from
@ -22,7 +22,7 @@ Development builds are available from
http://code.google.com/p/idapython/
RESOURCES
Resources
---------
The full function cross-reference is readable online at
@ -35,22 +35,23 @@ Mailing list for the project is hosted by Google Groups at
http://groups.google.com/group/idapython
INSTALLATION FROM BINARIES
Installation from binaries
--------------------------
1. Install 2.6 or 2.7 from http://www.python.org/
2. Copy "python" directory to %IDADIR%
3. Copy "plugins" directory to the %IDADIR%\plugins\
2. Copy the whole "python" directory to %IDADIR%
3. Copy the contents of the "plugins" directory to the %IDADIR%\plugins\
4. Copy "python.cfg" to %IDADIR%\cfg
USAGE
Usage
-----
- Run script: File / Script file (Alt-F7)
- Execute Python statement(s) (Ctrl-F3)
- Run previously executed script again: View / Recent Scripts (Alt+F9)
Batch mode execution:
* Batch mode execution:
Start IDA with the following command line options:
@ -75,7 +76,7 @@ Where N can be:
1: run script when UI is ready
2: run script immediately on plugin load (shortly after IDA starts and before processor modules and loaders)
User init file:
* User init file
You can place your custom settings to a file called 'idapythonrc.py'
that should be placed to
@ -89,3 +90,25 @@ or
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.
* Invoking Python from IDC
The IDAPython plugin exposes a new IDC function "RunPythonStatement(string idc_code)" that allows execution
of Python code from IDC
* Invoking IDC from Python
It is possible to use the idc.Eval() to evaluate IDC expressions from Python
* Making Python the default language
By default, IDA will use IDC to evaluate expressions. It is possible to change the default language to use
Python instead of IDC.
In order to do that, please use the following IDC code:
RunPlugin("python", 3)
To disable Python language and revert back to IDC:
RunPlugin("python", 4)

View File

@ -20,7 +20,7 @@ PLUGIN_TEST = 0
# -----------------------------------------------------------------------
# Configuration file
VT_CFGFILE = idaapi.get_user_idadir() + os.sep + "virustotal.cfg"
VT_CFGFILE = os.path.join(idaapi.get_user_idadir(), "virustotal.cfg")
# -----------------------------------------------------------------------
# VirusTotal Icon in PNG format

View File

@ -1,8 +1,8 @@
#!/usr/bin/env python
#---------------------------------------------------------------------
# IDAPython - Python plugin for Interactive Disassembler Pro
# IDAPython - Python plugin for Interactive Disassembler
#
# Copyright (c) 2004-2010 Gergely Erdelyi <gergely.erdelyi@d-dome.net>
# (c) The IDAPython Team <idapython@googlegroups.com>
#
# All rights reserved.
#
@ -24,19 +24,19 @@ from distutils import sysconfig
VERBOSE = True
IDA_MAJOR_VERSION = 6
IDA_MINOR_VERSION = 1
IDA_MINOR_VERSION = 2
if 'IDA' in os.environ:
IDA_SDK = os.environ['IDA']
else:
IDA_SDK = ".." + os.sep + "swigsdk-versions" + os.sep + "%d.%d" % (IDA_MAJOR_VERSION, IDA_MINOR_VERSION)
IDA_SDK = os.path.join("..", "swigsdk-versions", ("%d.%d" % (IDA_MAJOR_VERSION, IDA_MINOR_VERSION)))
# End of user configurable options
# IDAPython version
VERSION_MAJOR = 1
VERSION_MINOR = 5
VERSION_PATCH = 2
VERSION_PATCH = 3
# Determine Python version
PYTHON_MAJOR_VERSION = int(platform.python_version()[0])
@ -72,6 +72,8 @@ BINDIST_MANIFEST = [
"docs/notes.txt",
"examples/chooser.py",
"examples/colours.py",
"examples/ex_idphook_asm.py",
"examples/ex_uirequests.py",
"examples/debughook.py",
"examples/ex_cli.py",
"examples/ex1.idc",
@ -87,6 +89,10 @@ BINDIST_MANIFEST = [
"examples/ex_choose2.py",
"examples/ex_debug_names.py",
"examples/ex_graph.py",
"examples/ex_hotkey.py",
"examples/ex_patch.py",
"examples/ex_expr.py",
"examples/ex_timer.py",
"examples/ex_dbg.py",
"examples/ex_custview.py",
"examples/ex_prefix_plugin.py",
@ -94,6 +100,7 @@ BINDIST_MANIFEST = [
"examples/ex_pyqt.py",
"examples/ex_askusingform.py",
"examples/ex_uihook.py",
"examples/ex_idphook_asm.py",
"examples/ex_imports.py"
]
@ -216,7 +223,7 @@ class GCCBuilder(BuilderBase):
self.include_delimiter = "-I"
self.macro_delimiter = "-D"
self.libpath_delimiter = "-L"
self.compiler_parameters = "-fpermissive"
self.compiler_parameters = "-fpermissive -Wno-write-strings"
self.linker_parameters = "-shared"
self.basemacros = [ ]
self.compiler = "g++ -m32"
@ -279,8 +286,8 @@ def build_distribution(manifest, distrootdir, ea64, nukeold):
if type(f) == types.TupleType:
srcfilepath = f[0]
srcfilename = os.path.basename(srcfilepath)
dstdir = distrootdir + os.sep + f[1]
dstfilepath = dstdir + os.sep + srcfilename
dstdir = os.path.join(distrootdir, f[1])
dstfilepath = os.path.join(dstdir, srcfilename)
else:
srcfilepath = f
srcfilename = os.path.basename(f)
@ -288,12 +295,12 @@ def build_distribution(manifest, distrootdir, ea64, nukeold):
if srcdir == "":
dstdir = distrootdir
else:
dstdir = distrootdir + os.sep + srcdir
dstdir = os.path.join(distrootdir, srcdir)
if not os.path.exists(dstdir):
os.makedirs(dstdir)
dstfilepath = dstdir + os.sep + srcfilename
dstfilepath = os.path.join(dstdir, srcfilename)
shutil.copyfile(srcfilepath, dstfilepath)
zip.write(dstfilepath)
@ -304,14 +311,14 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
global SWIG_OPTIONS
""" Build the plugin from the SWIG wrapper and plugin main source """
# Path to the IDA SDK headers
ida_include_directory = idasdkdir + os.sep + "include"
ida_include_directory = os.path.join(idasdkdir, "include")
builder = None
# Platform-specific settings for the Linux build
if platform == "linux":
builder = GCCBuilder()
platform_macros = [ "__LINUX__" ]
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "lib"
python_libpath = os.path.join(sysconfig.EXEC_PREFIX, "lib")
python_library = "-lpython%d.%d" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION)
ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "x86_linux_gcc_64" or "x86_linux_gcc_32")
ida_lib = ""
@ -320,7 +327,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
elif platform == "win32":
builder = MSVCBuilder()
platform_macros = [ "__NT__" ]
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "libs"
python_libpath = os.path.join(sysconfig.EXEC_PREFIX, "libs")
python_library = "python%d%d.lib" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION)
ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "x86_win_vc_64" or "x86_win_vc_32")
ida_lib = "ida.lib"

View File

@ -9,7 +9,7 @@ from idaapi import Choose
#
# Modal chooser
#
#
# Get a modal Choose instance
chooser = Choose([], "MyChooser", 1)
@ -21,28 +21,30 @@ chooser.width = 50
ch = chooser.choose()
# Print the results
if ch > 0:
print "You chose %d which is %s" % (ch, chooser.list[ch-1])
print "You chose %d which is %s" % (ch, chooser.list[ch-1])
else:
print "Escape from chooser"
print "Escape from chooser"
#
# Normal chooser
#
class MyChoose(Choose):
"""
You have to subclass Chooser to override the enter() method
"""
def __init__(self, list=[], name="Choose"):
Choose.__init__(self, list, name)
# Set the width
self.width = 50
"""
You have to subclass Chooser to override the enter() method
"""
def __init__(self, list=[], name="Choose"):
Choose.__init__(self, list, name)
# Set the width
self.width = 50
self.deflt = 1
def enter(self, n):
print "Enter called. Do some stuff here."
print "The chosen item is %d = %s" % (n, self.list[n-1])
print "Now press ESC to leave."
def enter(self, n):
print "Enter called. Do some stuff here."
print "The chosen item is %d = %s" % (n, self.list[n-1])
print "Now press ESC to leave."
# Get a Choose instance
chooser = MyChoose([ "First", "Second", "Third" ], "MyChoose")
# Run the chooser
ch = chooser.choose()

View File

@ -16,16 +16,17 @@ class MyDbgHook(DBG_Hooks):
def dbg_process_start(self, pid, tid, ea, name, base, size):
print("Process started, pid=%d tid=%d name=%s" % (pid, tid, name))
return 0
def dbg_process_exit(self, pid, tid, ea, code):
print("Process exited pid=%d tid=%d ea=0x%x code=%d" % (pid, tid, ea, code))
return 0
def dbg_library_unload(self, pid, tid, ea, info):
print("Library unloaded: pid=%d tid=%d ea=0x%x info=%s" % (pid, tid, ea, info))
return 0
def dbg_process_attach(self, pid, tid, ea, name, base, size):
print("Process attach pid=%d tid=%d ea=0x%x name=%s base=%x size=%x" % (pid, tid, ea, name, base, size))
def dbg_process_detach(self, pid, tid, ea):
print("Process detached, pid=%d tid=%d ea=0x%x" % (pid, tid, ea))
return 0
@ -57,15 +58,19 @@ class MyDbgHook(DBG_Hooks):
def dbg_trace(self, tid, ea):
print("Trace tid=%d ea=0x%x" % (tid, ea))
# return values:
# 1 - do not log this trace event;
# 0 - log it
return 0
def dbg_step_into(self):
print("Step into")
return self.dbg_step_over()
self.dbg_step_over()
def dbg_run_to(self, pid, tid=0, ea=0):
print "Runto: tid=%d" % tid
idaapi.continue_process()
# def dbg_run_to(self, tid):
# print "Runto: tid=%d" % tid
# idaapi.continue_process()
def dbg_step_over(self):
eip = GetRegValue("EIP")
@ -76,7 +81,7 @@ class MyDbgHook(DBG_Hooks):
request_exit_process()
else:
request_step_over()
return 0
# Remove an existing debug hook
try:

View File

@ -218,6 +218,148 @@ using address %$
if ok == 1:
print("You entered: %x" % num.value)
# --------------------------------------------------------------------------
def test_multilinetext_legacy():
# Here we text the multi line text control in legacy mode
# Sample form from kernwin.hpp
s = """Sample dialog box
This is sample dialog box
<Enter multi line text:t40:80:50::>
"""
# Use either StringArgument or NumericArgument to pass values to the function
ti = textctrl_info_t("Some initial value")
ok = idaapi.AskUsingForm(s, pointer(c_void_p.from_address(ti.clink_ptr)))
if ok == 1:
print("You entered: %s" % ti.text)
del ti
# --------------------------------------------------------------------------
class MyForm2(Form):
"""Simple Form to test multilinetext and combo box controls"""
def __init__(self):
Form.__init__(self, r"""STARTITEM 0
BUTTON YES* Yeah
BUTTON NO Nope
BUTTON CANCEL NONE
Form Test
{FormChangeCb}
<Multilinetext:{txtMultiLineText}>
""", {
'txtMultiLineText': Form.MultiLineTextControl(text="Hello"),
'FormChangeCb': Form.FormChangeCb(self.OnFormChange),
})
def OnFormChange(self, fid):
if fid == self.txtMultiLineText.id:
pass
elif fid == -2:
ti = self.GetControlValue(self.txtMultiLineText)
print "ti.text = %s" % ti.text
else:
print(">>fid:%d" % fid)
return 1
# --------------------------------------------------------------------------
def test_multilinetext(execute=True):
"""Test the multilinetext and combobox controls"""
f = MyForm2()
f, args = f.Compile()
if execute:
ok = f.Execute()
else:
print args[0]
print args[1:]
ok = 0
if ok == 1:
assert f.txtMultiLineText.text == f.txtMultiLineText.value
print f.txtMultiLineText.text
f.Free()
# --------------------------------------------------------------------------
class MyForm3(Form):
"""Simple Form to test multilinetext and combo box controls"""
def __init__(self):
self.__n = 0
Form.__init__(self,
r"""BUTTON YES* Yeah
BUTTON NO Nope
BUTTON CANCEL NONE
Dropdown list test
{FormChangeCb}
<Dropdown list (readonly):{cbReadonly}> <Add element:{iButtonAddelement}> <Set index:{iButtonSetIndex}>
<Dropdown list (editable):{cbEditable}> <Set string:{iButtonSetString}>
""", {
'FormChangeCb': Form.FormChangeCb(self.OnFormChange),
'cbReadonly': Form.DropdownListControl(
items=["red", "green", "blue"],
readonly=True,
selval=1),
'cbEditable': Form.DropdownListControl(
items=["1MB", "2MB", "3MB", "4MB"],
readonly=False,
selval="4MB"),
'iButtonAddelement': Form.ButtonInput(self.OnButtonNop),
'iButtonSetIndex': Form.ButtonInput(self.OnButtonNop),
'iButtonSetString': Form.ButtonInput(self.OnButtonNop),
})
def OnButtonNop(self, code=0):
"""Do nothing, we will handle events in the form callback"""
pass
def OnFormChange(self, fid):
if fid == self.iButtonSetString.id:
s = idc.AskStr("none", "Enter value")
if s:
self.SetControlValue(self.cbEditable, s)
elif fid == self.iButtonSetIndex.id:
s = idc.AskStr("1", "Enter index value:")
if s:
try:
i = int(s)
except:
i = 0
self.SetControlValue(self.cbReadonly, i)
elif fid == self.iButtonAddelement.id:
# add a value to the string list
self.__n += 1
self.cbReadonly.add("some text #%d" % self.__n)
# Refresh the control
self.RefreshField(self.cbReadonly)
elif fid == -2:
s = self.GetControlValue(self.cbEditable)
print "user entered: %s" % s
sel_idx = self.GetControlValue(self.cbReadonly)
return 1
# --------------------------------------------------------------------------
def test_dropdown(execute=True):
"""Test the combobox controls"""
f = MyForm3()
f, args = f.Compile()
if execute:
ok = f.Execute()
else:
print args[0]
print args[1:]
ok = 0
if ok == 1:
print "Editable: %s" % f.cbEditable.value
print "Readonly: %s" % f.cbReadonly.value
f.Free()
#</pycode(ex_askusingform)>

View File

@ -3,12 +3,13 @@ from idaapi import Choose2
class MyChoose2(Choose2):
def __init__(self, title, nb = 5):
def __init__(self, title, nb = 5, deflt=1):
Choose2.__init__(self, title, [ ["Address", 10], ["Name", 30] ])
self.n = 0
self.items = [ self.make_item() for x in xrange(0, nb+1) ]
self.icon = 5
self.selcount = 0
self.deflt = deflt
self.popup_names = ["Inzert", "Del leet", "Ehdeet", "Ree frech"]
print("created %s" % str(self))
@ -79,6 +80,6 @@ class MyChoose2(Choose2):
return [0xFF0000, 0]
for i in xrange(1, 5+1):
c = MyChoose2("choose2 - sample %d" % i, i*2)
c = MyChoose2("choose2 - sample %d" % i, i*2, deflt=i)
r = c.show()
print r

16
examples/ex_expr.py Normal file
View File

@ -0,0 +1,16 @@
# -----------------------------------------------------------------------
# This is an example illustrating how to extend IDC from Python
# (c) Hex-Rays
#
from idaapi import set_idc_func_ex
#<pycode(ex_expr)>
def py_power(n, e):
return n ** e
ok = set_idc_func_ex("pow", py_power, (idaapi.VT_LONG, idaapi.VT_LONG), 0)
if ok:
print("Now the pow() will be present IDC!")
else:
print("Failed to register pow() IDC function")
#</pycode(ex_expr)>

25
examples/ex_hotkey.py Normal file
View File

@ -0,0 +1,25 @@
#---------------------------------------------------------------------
# This script demonstrates the usage of hotkeys.
#
#
# Author: IDAPython team
#---------------------------------------------------------------------
import idaapi
def hotkey_pressed():
print("hotkey pressed!")
try:
hotkey_ctx
if idaapi.del_hotkey(hotkey_ctx):
print("Hotkey unregistered!")
del hotkey_ctx
else:
print("Failed to delete hotkey!")
except:
hotkey_ctx = idaapi.add_hotkey("Shift-A", hotkey_pressed)
if hotkey_ctx is None:
print("Failed to register hotkey!")
del hotkey_ctx
else:
print("Hotkey registered!")

View File

@ -0,0 +1,48 @@
import idaapi
import idautils
"""
This is a sample plugin for extending the assemble().
We add support for assembling the following pseudo instructions:
- "zero eax" -> xor eax, eax
- "nothing" -> nop
(c) Hex-Rays
"""
#--------------------------------------------------------------------------
class assemble_idp_hook_t(idaapi.IDP_Hooks):
def __init__(self):
idaapi.IDP_Hooks.__init__(self)
def assemble(self, ea, cs, ip, use32, line):
line = line.strip()
if line == "xor eax, eax":
return "\x33\xC0"
elif line == "nop":
# Decode current instruction to figure out its size
cmd = idautils.DecodeInstruction(ea)
if cmd:
# NOP all the instruction bytes
return "\x90" * cmd.size
return None
#---------------------------------------------------------------------
# Remove an existing hook on second run
try:
idp_hook_stat = "un"
print("IDP hook: checking for hook...")
idphook
print("IDP hook: unhooking....")
idphook.unhook()
del idphook
except:
print("IDP hook: not installed, installing now....")
idp_hook_stat = ""
idphook = assemble_idp_hook_t()
idphook.hook()
print("IDP hook %sinstalled. Run the script again to %sinstall" % (idp_hook_stat, idp_hook_stat))

36
examples/ex_patch.py Normal file
View File

@ -0,0 +1,36 @@
# -------------------------------------------------------------------------
# This is an example illustrating how to visit all patched bytes in Python
# (c) Hex-Rays
import idaapi
# -------------------------------------------------------------------------
class patched_bytes_visitor(object):
def __init__(self):
self.skip = 0
self.patch = 0
def __call__(self, ea, fpos, o, v, cnt=()):
if fpos == -1:
self.skip += 1
print(" ea: %x o: %x v: %x...skipped" % (ea, fpos, o, v))
else:
self.patch += 1
print(" ea: %x fpos: %x o: %x v: %x" % (ea, fpos, o, v))
return 0
# -------------------------------------------------------------------------
def main():
print("Visiting all patched bytes:")
v = patched_bytes_visitor()
r = idaapi.visit_patched_bytes(0, idaapi.BADADDR, v)
if r != 0:
print("visit_patched_bytes() returned %d" % r)
else:
print("Patched: %d Skipped: %d" % (v.patch, v.skip))
# -------------------------------------------------------------------------
if __name__ == '__main__':
main()

38
examples/ex_timer.py Normal file
View File

@ -0,0 +1,38 @@
# -------------------------------------------------------------------------
# This is an example illustrating how to use timers
# (c) Hex-Rays
import idaapi
# -------------------------------------------------------------------------
class timercallback_t(object):
def __init__(self):
self.interval = 1000
self.obj = idaapi.register_timer(self.interval, self)
if self.obj is None:
raise RuntimeError, "Failed to register timer"
self.times = 5
def __call__(self):
print("Timer invoked. %d time(s) left" % self.times)
self.times -= 1
# Unregister the timer when the counter reaches zero
return -1 if self.times == 0 else self.interval
def __del__(self):
print("Timer object disposed %s" % id(self))
# -------------------------------------------------------------------------
def main():
try:
t = timercallback_t()
# No need to unregister the timer.
# It will unregister itself in the callback when it returns -1
except Exception as e:
print "Error: %s" % e
# -------------------------------------------------------------------------
if __name__ == '__main__':
main()

75
examples/ex_uirequests.py Normal file
View File

@ -0,0 +1,75 @@
# -----------------------------------------------------------------------
# This is an example illustrating how to use the execute_ui_requests()
# and the idautils.ProcessUiActions()
# (c) Hex-Rays
#
import idaapi
import idautils
import idc
# --------------------------------------------------------------------------
class __process_ui_actions_helper(object):
def __init__(self, actions, flags = 0):
"""Expect a list or a string with a list of actions"""
if isinstance(actions, str):
lst = actions.split(";")
elif isinstance(actions, (list, tuple)):
lst = actions
else:
raise ValueError, "Must pass a string, list or a tuple"
# Remember the action list and the flags
self.__action_list = lst
self.__flags = flags
# Reset action index
self.__idx = 0
def __len__(self):
return len(self.__action_list)
def __call__(self):
if self.__idx >= len(self.__action_list):
return False
# Execute one action
idaapi.process_ui_action(
self.__action_list[self.__idx],
self.__flags)
# Move to next action
self.__idx += 1
print "index=%d" % self.__idx
# Reschedule
return True
# --------------------------------------------------------------------------
def ProcessUiActions(actions, flags=0):
"""
@param actions: A string containing a list of actions separated by semicolon, a list or a tuple
@param flags: flags to be passed to process_ui_action()
@return: Boolean. Returns False if the action list was empty or execute_ui_requests() failed.
"""
# Instantiate a helper
helper = __process_ui_actions_helper(actions, flags)
return False if len(helper) < 1 else idaapi.execute_ui_requests((helper,))
# --------------------------------------------------------------------------
class print_req_t(object):
def __init__(self, s):
self.s = s
def __call__(self):
idaapi.msg("%s" % self.s)
return False # Don't reschedule
if idc.AskYN(1,("HIDECANCEL\nDo you want to run execute_ui_requests() example?\n"
"Press NO to execute ProcessUiActions() example\n")):
idaapi.execute_ui_requests(
(print_req_t("Hello"), print_req_t(" world\n")) )
else:
ProcessUiActions("JumpQ;JumpName")

View File

@ -5,9 +5,6 @@ ALERT_AUTO_SCRIPTS = 1
// Remove current directory from import search path
REMOVE_CWD_SYS_PATH = 0
// Execute statement hotkey
EXEC_STATEMENT_HOTKEY = "Ctrl-F7";
// Script timeout (in seconds)
// (A value of 0 disables the timeout)
SCRIPT_TIMEOUT = 3

View File

@ -1,5 +1,5 @@
//---------------------------------------------------------------------
// IDAPython - Python plugin for Interactive Disassembler Pro
// IDAPython - Python plugin for Interactive Disassembler
//
// Copyright (c) The IDAPython Team <idapython@googlegroups.com>
//
@ -42,7 +42,7 @@
// Python-style version tuple comes from the makefile
// Only the serial and status is set here
#define VER_SERIAL 3
#define VER_SERIAL 0
#define VER_STATUS "final"
#define IDAPYTHON_RUNSTATEMENT 0
#define IDAPYTHON_ENABLE_EXTLANG 3
@ -75,11 +75,9 @@ enum script_run_when
//-------------------------------------------------------------------------
// Global variables
static bool g_initialized = false;
static bool g_menu_installed = false;
static int g_run_when = -1;
static char g_run_script[QMAXPATH];
static char g_idapython_dir[QMAXPATH];
static char g_runstmt_hotkey[30] = "Ctrl-F3";
//-------------------------------------------------------------------------
// Prototypes and forward declarations
@ -223,123 +221,23 @@ int set_script_timeout(int timeout)
return timeout;
}
//-------------------------------------------------------------------------
// Converts IDC arguments to Python argument list or just one tuple
// If 'decref' is NULL then 'pargs' will contain one element which is the tuple
static bool convert_args(
const idc_value_t args[],
int nargs,
ppyobject_vec_t &pargs,
boolvec_t *decref,
char *errbuf,
size_t errbufsize)
{
bool as_tupple = decref == NULL;
PyObject *py_tuple(NULL);
pargs.qclear();
if ( as_tupple )
{
py_tuple = PyTuple_New(nargs);
if ( py_tuple == NULL )
{
qstrncpy(errbuf, "Failed to create a new tuple to store arguments!", errbufsize);
return false;
}
// Add the tuple
pargs.push_back(py_tuple);
}
else
{
decref->qclear();
}
for ( int i=0; i<nargs; i++ )
{
PyObject *py_obj(NULL);
int cvt = idcvar_to_pyvar(args[i], &py_obj);
if ( cvt < CIP_OK )
{
qsnprintf(errbuf, errbufsize, "arg#%d has wrong type %d", i, args[i].vtype);
return false;
}
if ( as_tupple )
{
// Opaque object?
if ( cvt == CIP_OK_NODECREF )
{
// Increment reference for opaque objects.
// (A tupple will steal references of its set items,
// and for an opaque object we want it to still exist
// even if the tuple is gone)
Py_INCREF(py_obj);
}
// Save argument
PyTuple_SetItem(py_tuple, i, py_obj);
}
else
{
pargs.push_back(py_obj);
// do not decrement reference of opaque objects
decref->push_back(cvt == CIP_OK);
}
}
return true;
}
//-------------------------------------------------------------------------
// Frees arguments returned by convert_args()
static void free_args(
ppyobject_vec_t &pargs,
boolvec_t *decref = NULL)
{
if ( decref == NULL )
{
if ( !pargs.empty() )
Py_XDECREF(pargs[0]);
}
else
{
// free argument objects
for ( int i=(int)pargs.size()-1; i>=0; i-- )
{
if ( decref->at(i) )
Py_DECREF(pargs[i]);
}
decref->clear();
}
pargs.clear();
}
//------------------------------------------------------------------------
// Return a formatted error or just print it to the console
static void handle_python_error(char *errbuf, size_t errbufsize)
static void handle_python_error(
char *errbuf,
size_t errbufsize,
bool clear_error = true)
{
if ( errbufsize > 0 )
errbuf[0] = '\0';
// No exception?
if ( !PyErr_Occurred() )
return;
PyObject *result;
PyObject *ptype, *pvalue, *ptraceback;
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
result = PyObject_Str(pvalue);
if ( result != NULL )
{
qsnprintf(errbuf, errbufsize, "ERROR: %s", PyString_AsString(result));
PyErr_Clear();
Py_XDECREF(ptype);
Py_XDECREF(pvalue);
Py_XDECREF(ptraceback);
Py_DECREF(result);
}
else
{
PyErr_Print();
}
qstring s;
if ( PyW_GetError(&s, clear_error) )
qstrncpy(errbuf, s.c_str(), errbufsize);
}
//------------------------------------------------------------------------
@ -391,23 +289,26 @@ static void PythonEvalOrExec(
}
//------------------------------------------------------------------------
// Simple Python statement runner function for IDC
static const char idc_runpythonstatement_args[] = { VT_STR2, 0 };
static error_t idaapi idc_runpythonstatement(idc_value_t *argv, idc_value_t *res)
// Executes a simple string
static bool idaapi IDAPython_extlang_run_statements(
const char *str,
char *errbuf,
size_t errbufsize)
{
PyObject *globals = GetMainGlobals();
bool ok;
if ( globals == NULL )
{
res->set_string("internal error");
ok = false;
}
else
{
errbuf[0] = '\0';
PyErr_Clear();
begin_execution();
PYW_GIL_ENSURE;
PyObject *result = PyRun_String(
argv[0].c_str(),
str,
Py_file_input,
globals,
globals);
@ -415,21 +316,31 @@ static error_t idaapi idc_runpythonstatement(idc_value_t *argv, idc_value_t *res
Py_XDECREF(result);
end_execution();
if ( result == NULL || PyErr_Occurred() )
{
char errbuf[MAXSTR];
handle_python_error(errbuf, sizeof(errbuf));
if ( errbuf[0] == '\0' )
res->set_string("internal error");
else
res->set_string(errbuf);
}
else
{
// success
res->set_long(0);
}
ok = result != NULL && !PyErr_Occurred();
if ( !ok )
handle_python_error(errbuf, errbufsize);
}
if ( !ok && errbuf[0] == '\0' )
qstrncpy(errbuf, "internal error", errbufsize);
return ok;
}
//------------------------------------------------------------------------
// Simple Python statement runner function for IDC
static const char idc_runpythonstatement_args[] = { VT_STR2, 0 };
static error_t idaapi idc_runpythonstatement(
idc_value_t *argv,
idc_value_t *res)
{
char errbuf[MAXSTR];
bool ok = IDAPython_extlang_run_statements(argv[0].c_str(), errbuf, sizeof(errbuf));
if ( ok )
res->set_long(0);
else
res->set_string(errbuf);
return eOk;
}
@ -441,15 +352,7 @@ const char *idaapi set_python_options(
{
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 ( value_type == IDPOPT_NUM )
{
if ( qstrcmp(keyword, "SCRIPT_TIMEOUT") == 0 )
{
@ -567,7 +470,7 @@ static bool IDAPython_ExecFile(const char *FileName, char *errbuf, size_t errbuf
char script[MAXSTR];
qstrncpy(script, FileName, sizeof(script));
strrpl(script, '\\', '//');
strrpl(script, '\\', '/');
PyObject *py_script = PyString_FromString(script);
PYW_GIL_ENSURE;
@ -754,7 +657,7 @@ bool idaapi IDAPython_extlang_run(
do
{
// Convert arguments to python
ok = convert_args(args, nargs, pargs, &decref, errbuf, errbufsize);
ok = pyw_convert_idc_args(args, nargs, pargs, &decref, errbuf, errbufsize);
if ( !ok )
break;
@ -792,7 +695,7 @@ bool idaapi IDAPython_extlang_run(
ok = return_python_result(result, pres, errbuf, errbufsize);
} while ( false );
free_args(pargs, &decref);
pyw_free_idc_args(pargs, &decref);
if ( imported_module )
Py_XDECREF(module);
@ -851,7 +754,7 @@ bool idaapi IDAPython_extlang_create_object(
}
// Error during conversion?
ok = convert_args(args, nargs, pargs, NULL, errbuf, errbufsize);
ok = pyw_convert_idc_args(args, nargs, pargs, NULL, errbuf, errbufsize);
if ( !ok )
break;
ok = false;
@ -867,7 +770,7 @@ bool idaapi IDAPython_extlang_create_object(
Py_XDECREF(py_cls);
// Free the arguments tuple
free_args(pargs);
pyw_free_idc_args(pargs);
return ok;
}
@ -918,9 +821,41 @@ bool idaapi IDAPython_extlang_get_attr(
// No object specified:
else
{
// then work with main module
// ...then work with main module
py_obj = py_mod;
}
// Special case: if attribute not passed then retrieve the class
// name associated associated with the passed object
if ( attr == NULL || attr[0] == '\0' )
{
cvt = CIP_FAILED;
// Get the class
PyObject *cls = PyObject_GetAttrString(py_obj, "__class__");
if ( cls == NULL )
break;
// Get its name
PyObject *name = PyObject_GetAttrString(cls, "__name__");
Py_DECREF(cls);
if ( name == NULL )
break;
// Convert name object to string object
PyObject *string = PyObject_Str(name);
Py_DECREF(name);
if ( string == NULL )
break;
// Convert name python string to a C string
const char *clsname = PyString_AsString(name);
if ( clsname == NULL )
break;
result->set_string(clsname);
cvt = CIP_OK;
break;
}
PyObject *py_attr = PyW_TryGetAttrString(py_obj, attr);
// No attribute?
if ( py_attr == NULL )
@ -1089,7 +1024,7 @@ bool idaapi IDAPython_extlang_call_method(
}
// Convert arguments to python objects
ok = convert_args(args, nargs, pargs, NULL, errbuf, errbufsize);
ok = pyw_convert_idc_args(args, nargs, pargs, NULL, errbuf, errbufsize);
if ( !ok )
break;
@ -1100,7 +1035,7 @@ bool idaapi IDAPython_extlang_call_method(
} while ( false );
// Free converted args
free_args(pargs);
pyw_free_idc_args(pargs);
// Release reference of object if needed
if ( obj_cvt != CIP_OK_NODECREF )
@ -1124,7 +1059,8 @@ extlang_t extlang_python =
IDAPython_extlang_create_object,
IDAPython_extlang_get_attr,
IDAPython_extlang_set_attr,
IDAPython_extlang_call_method
IDAPython_extlang_call_method,
IDAPython_extlang_run_statements,
};
//-------------------------------------------------------------------------
@ -1247,26 +1183,6 @@ void py_print_banner()
PYW_GIL_RELEASE;
}
//-------------------------------------------------------------------------
// Install python menu items
static void install_python_menus()
{
if ( g_menu_installed )
return;
// Add menu items for all the functions
// Note: Different paths are used for the GUI version
add_menu_item(
"File/IDC command...",
"P~y~thon command...",
g_runstmt_hotkey,
SETMENU_APP,
IDAPython_Menu_Callback,
(void *)IDAPYTHON_RUNSTATEMENT);
g_menu_installed = true;
}
//------------------------------------------------------------------------
// Parse plugin options
void parse_plugin_options()
@ -1331,7 +1247,6 @@ static int idaapi menu_installer_cb(void *, int code, va_list)
case ui_ready_to_run:
g_ui_ready = true;
py_print_banner();
install_python_menus();
if ( g_run_when == run_on_ui_ready )
RunScript(g_run_script);
@ -1429,7 +1344,8 @@ bool IDAPython_Init(void)
init_idaapi();
// Set IDAPYTHON_VERSION in Python
qsnprintf(tmp, sizeof(tmp), "IDAPYTHON_VERSION=(%d, %d, %d, '%s', %d)\n"
qsnprintf(tmp, sizeof(tmp),
"IDAPYTHON_VERSION=(%d, %d, %d, '%s', %d)\n"
"IDAPYTHON_REMOVE_CWD_SYS_PATH = %s\n",
VER_MAJOR,
VER_MINOR,
@ -1447,8 +1363,17 @@ bool IDAPython_Init(void)
qmakepath(tmp, MAXSTR, g_idapython_dir, S_INIT_PY, NULL);
if ( !PyRunFile(tmp) )
{
handle_python_error(tmp, sizeof(tmp));
warning("IDAPython: error executing " S_INIT_PY ":\n%s", tmp);
// Try to fetch a one line error string. We must do it before printing
// the traceback information. Make sure that the exception is not cleared
handle_python_error(tmp, sizeof(tmp), false);
// Print the exception traceback
PyRun_SimpleString("import traceback;traceback.print_exc();");
warning("IDAPython: error executing " S_INIT_PY ":\n"
"%s\n"
"\n"
"Refer to the message window to see the full error log.", tmp);
return false;
}
@ -1497,7 +1422,6 @@ void IDAPython_Term(void)
#endif
/* Remove the menu items before termination */
del_menu_item("File/Python command...");
g_menu_installed = false;
// Notify about IDA closing
pywraps_nw_notify(NW_TERMIDA_SLOT);

View File

@ -1,5 +1,5 @@
#---------------------------------------------------------------------
# IDAPython - Python plugin for Interactive Disassembler Pro
# IDAPython - Python plugin for Interactive Disassembler
#
# Copyright (c) 2004-2010 Gergely Erdelyi <gergely.erdelyi@d-dome.net>
#
@ -310,6 +310,38 @@ def FuncItems(start):
ok = fii.next_code()
def Structs():
"""
Get a list of structures
@return: List of tuples (idx, sid, name)
"""
idx = idc.GetFirstStrucIdx()
while idx != idaapi.BADADDR:
sid = idc.GetStrucId(idx)
yield (idx, sid, idc.GetStrucName(sid))
idx = idc.GetNextStrucIdx(idx)
def StructMembers(sid):
"""
Get a list of structure members information.
@param sid: ID of the structure.
@return: List of tuples (offset, name, size)
@note: If 'sid' does not refer to a valid structure,
an exception will be raised.
"""
off = idc.GetFirstMember(sid)
if off == idaapi.BADNODE:
raise Exception("No structure with ID: 0x%x" % sid)
members = idc.GetMemberQty(sid)
for idx in range(0, members):
yield (off, idc.GetMemberName(sid, off), idc.GetMemberSize(sid, off))
off = idc.GetStrucNextOff(sid, off)
def DecodePrecedingInstruction(ea):
"""
@ -648,17 +680,69 @@ class _procregs(object):
def __setattr__(self, attr, value):
raise AttributeError(attr)
# -----------------------------------------------------------------------
class _cpu(object):
"Simple wrapper around GetRegValue/SetRegValue"
def __getattr__(self, name):
#print "cpu.get(%s)"%name
#print "cpu.get(%s)" % name
return idc.GetRegValue(name)
def __setattr__(self, name, value):
#print "cpu.set(%s)"%name
#print "cpu.set(%s)" % name
return idc.SetRegValue(value, name)
# --------------------------------------------------------------------------
class __process_ui_actions_helper(object):
def __init__(self, actions, flags = 0):
"""Expect a list or a string with a list of actions"""
if isinstance(actions, str):
lst = actions.split(";")
elif isinstance(actions, (list, tuple)):
lst = actions
else:
raise ValueError, "Must pass a string, list or a tuple"
# Remember the action list and the flags
self.__action_list = lst
self.__flags = flags
# Reset action index
self.__idx = 0
def __len__(self):
return len(self.__action_list)
def __call__(self):
if self.__idx >= len(self.__action_list):
return False
# Execute one action
idaapi.process_ui_action(
self.__action_list[self.__idx],
self.__flags)
# Move to next action
self.__idx += 1
# Reschedule
return True
# --------------------------------------------------------------------------
def ProcessUiActions(actions, flags=0):
"""
@param actions: A string containing a list of actions separated by semicolon, a list or a tuple
@param flags: flags to be passed to process_ui_action()
@return: Boolean. Returns False if the action list was empty or execute_ui_requests() failed.
"""
# Instantiate a helper
helper = __process_ui_actions_helper(actions, flags)
return False if len(helper) < 1 else idaapi.execute_ui_requests((helper,))
# -----------------------------------------------------------------------
class peutils_t(object):
"""

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
#---------------------------------------------------------------------
# IDAPython - Python plugin for Interactive Disassembler Pro
# IDAPython - Python plugin for Interactive Disassembler
#
# Original IDC.IDC:
# Copyright (c) 1990-2010 Ilfak Guilfanov
@ -39,8 +39,7 @@ import time
import types
__EA64__ = idaapi.BADADDR == 0xFFFFFFFFFFFFFFFFL
WORDMASK = __EA64__ and 0xFFFFFFFFFFFFFFFF or 0xFFFFFFFF
WORDMASK = 0xFFFFFFFFFFFFFFFF if __EA64__ else 0xFFFFFFFF
class DeprecatedIDCError(Exception):
"""
Exception for deprecated function calls
@ -78,7 +77,7 @@ def _IDC_SetAttr(obj, attrmap, attroffs, value):
BADADDR = idaapi.BADADDR # Not allowed address value
BADSEL = idaapi.BADSEL # Not allowed selector value/number
MAXADDR = idaapi.MAXADDR & WORDMASK
SIZE_MAX = idaapi.SIZE_MAX
#
# Flag bit definitions (for GetFlags())
#
@ -838,6 +837,21 @@ def MakeStructEx(ea, size, strname):
return idaapi.doStruct(ea, size, strid)
def MakeCustomDataEx(ea, size, dtid, fid):
"""
Convert the item at address to custom data.
@param ea: linear address.
@param size: custom data size in bytes.
@param dtid: data type ID.
@param fid: data format ID.
@return: 1-ok, 0-failure
"""
return idaapi.doCustomData(ea, size, dtid, fid)
def MakeAlign(ea, count, align):
"""
Convert the current item to an alignment directive
@ -2021,9 +2035,7 @@ def ItemHead(ea):
@return: the starting address of the item
if the current address is unexplored, returns 'ea'
"""
if idaapi.isTail(idaapi.get_flags_novalue(ea)):
ea = idaapi.prev_not_tail(ea)
return ea
return idaapi.get_item_head(ea)
def ItemEnd(ea):
@ -2328,9 +2340,9 @@ def GetString(ea, length = -1, strtype = ASCSTR_C):
@return: string contents or empty string
"""
if length == -1:
length = idaapi.get_max_ascii_length(ea, strtype)
length = idaapi.get_max_ascii_length(ea, strtype, idaapi.ALOPT_IGNHEADS)
return idaapi.get_ascii_contents(ea, length, strtype, length + 1)
return idaapi.get_ascii_contents2(ea, length, strtype)
def GetStringType(ea):
@ -2935,7 +2947,7 @@ def AskLong(defval, prompt):
def ProcessUiAction(name, flags=0):
"""
Invokes an IDA Pro UI action by name
Invokes an IDA UI action by name
@param name: Command name
@param flags: Reserved. Must be zero
@ -4771,8 +4783,8 @@ def GetMemberQty(sid):
@return: -1 if bad structure type ID is passed otherwise
returns number of members.
@note: Union members are, in IDA's internals, located
at subsequent byte offsets: member 0 -> offset 0x0,
@note: Union members are, in IDA's internals, located
at subsequent byte offsets: member 0 -> offset 0x0,
member 1 -> offset 0x1, etc...
"""
s = idaapi.get_struc(sid)
@ -4797,8 +4809,8 @@ def GetStrucPrevOff(sid, offset):
It will return size of the structure if input
'offset' is bigger than the structure size.
@note: Union members are, in IDA's internals, located
at subsequent byte offsets: member 0 -> offset 0x0,
@note: Union members are, in IDA's internals, located
at subsequent byte offsets: member 0 -> offset 0x0,
member 1 -> offset 0x1, etc...
"""
s = idaapi.get_struc(sid)
@ -4826,8 +4838,8 @@ def GetStrucNextOff(sid, offset):
It will return size of the structure if input
'offset' belongs to the last member of the structure.
@note: Union members are, in IDA's internals, located
at subsequent byte offsets: member 0 -> offset 0x0,
@note: Union members are, in IDA's internals, located
at subsequent byte offsets: member 0 -> offset 0x0,
member 1 -> offset 0x1, etc...
"""
s = idaapi.get_struc(sid)
@ -4848,8 +4860,8 @@ def GetFirstMember(sid):
structure. It treats these 'holes'
as unnamed arrays of bytes.
@note: Union members are, in IDA's internals, located
at subsequent byte offsets: member 0 -> offset 0x0,
@note: Union members are, in IDA's internals, located
at subsequent byte offsets: member 0 -> offset 0x0,
member 1 -> offset 0x1, etc...
"""
s = idaapi.get_struc(sid)
@ -4873,8 +4885,8 @@ def GetLastMember(sid):
structure. It treats these 'holes'
as unnamed arrays of bytes.
@note: Union members are, in IDA's internals, located
at subsequent byte offsets: member 0 -> offset 0x0,
@note: Union members are, in IDA's internals, located
at subsequent byte offsets: member 0 -> offset 0x0,
member 1 -> offset 0x1, etc...
"""
s = idaapi.get_struc(sid)
@ -4895,8 +4907,8 @@ def GetMemberOffset(sid, member_name):
or no such member in the structure
otherwise returns offset of the specified member.
@note: Union members are, in IDA's internals, located
at subsequent byte offsets: member 0 -> offset 0x0,
@note: Union members are, in IDA's internals, located
at subsequent byte offsets: member 0 -> offset 0x0,
member 1 -> offset 0x1, etc...
"""
s = idaapi.get_struc(sid)
@ -5891,6 +5903,8 @@ def AddEnum(idx, name, flag):
@return: id of new enum or BADADDR
"""
if idx < 0:
idx = idx & SIZE_MAX
return idaapi.add_enum(idx, name, flag)
@ -6077,68 +6091,414 @@ def SetConstCmt(const_id, cmt, repeatable):
# A R R A Y S I N I D C
#----------------------------------------------------------------------------
_IDC_ARRAY_PREFIX = "$ idc_array "
def __l2m1(v):
"""
Long to minus 1: If the 'v' appears to be the
'signed long' version of -1, then return -1.
Otherwise, return 'v'.
"""
if v == idaapi.BADNODE:
return -1
else:
return v
AR_LONG = idaapi.atag
"""Array of longs"""
AR_STR = idaapi.stag
"""Array of strings"""
class __dummy_netnode(object):
"""
Implements, in an "always failing" fashion, the
netnode functions that are necessary for the
array-related functions.
The sole purpose of this singleton class is to
serve as a placeholder for netnode-manipulating
functions, that don't want to each have to perform
checks on the existence of the netnode.
(..in other words: it avoids a bunch of if/else's).
See __GetArrayById() for more info.
"""
def rename(self, *args): return 0
def kill(self, *args): pass
def index(self, *args): return -1
def altset(self, *args): return 0
def supset(self, *args): return 0
def altval(self, *args): return 0
def supval(self, *args): return 0
def altdel(self, *args): return 0
def supdel(self, *args): return 0
def alt1st(self, *args): return -1
def sup1st(self, *args): return -1
def altlast(self, *args): return -1
def suplast(self, *args): return -1
def altnxt(self, *args): return -1
def supnxt(self, *args): return -1
def altprev(self, *args): return -1
def supprev(self, *args): return -1
def hashset(self, *args): return 0
def hashval(self, *args): return 0
def hashstr(self, *args): return 0
def hashstr_buf(self, *args): return 0
def hashset_idx(self, *args): return 0
def hashset_buf(self, *args): return 0
def hashval_long(self, *args): return 0
def hashdel(self, *args): return 0
def hash1st(self, *args): return 0
def hashnxt(self, *args): return 0
def hashprev(self, *args): return 0
def hashlast(self, *args): return 0
__dummy_netnode.instance = __dummy_netnode()
def __GetArrayById(array_id):
"""
Get an array, by its ID.
This (internal) wrapper around 'idaaip.netnode(array_id)'
will ensure a certain safety around the retrieval of
arrays (by catching quite unexpect[ed|able] exceptions,
and making sure we don't create & use `transient' netnodes).
@param array_id: A positive, valid array ID.
"""
try:
node = idaapi.netnode(array_id)
nodename = node.name()
if nodename is None or not nodename.startswith(_IDC_ARRAY_PREFIX):
return __dummy_netnode.instance
else:
return node
except NotImplementedError:
return __dummy_netnode.instance
def CreateArray(name):
raise DeprecatedIDCError, "Use python pickles instead."
"""
Create array.
@param name: The array name.
@return: -1 in case of failure, a valid array_id otherwise.
"""
node = idaapi.netnode()
res = node.create(_IDC_ARRAY_PREFIX + name)
if res == False:
return -1
else:
return node.index()
def GetArrayId(name):
raise DeprecatedIDCError, "Use python pickles instead."
"""
Get array array_id, by name.
def RenameArray(hashid, newname):
raise DeprecatedIDCError, "Use python pickles instead."
@param name: The array name.
def DeleteArray(hashid):
raise DeprecatedIDCError, "Use python pickles instead."
@return: -1 in case of failure (i.e., no array with that
name exists), a valid array_id otherwise.
"""
return __l2m1(idaapi.netnode(_IDC_ARRAY_PREFIX + name, 0, False).index())
def SetArrayLong(hashid, idx, value):
raise DeprecatedIDCError, "Use python pickles instead."
def SetArrayString(hashid, idx, s):
raise DeprecatedIDCError, "Use python pickles instead."
def RenameArray(array_id, newname):
"""
Rename array, by its ID.
def GetArrayElement(tag, hashid, idx):
raise DeprecatedIDCError, "Use python pickles instead."
@param id: The ID of the array to rename.
@param newname: The new name of the array.
def DelArrayElement(tag, hashid, idx):
raise DeprecatedIDCError, "Use python pickles instead."
@return: 1 in case of success, 0 otherwise
"""
return __GetArrayById(array_id).rename(_IDC_ARRAY_PREFIX + newname) == 1
def GetFirstIndex(tag, hashid):
raise DeprecatedIDCError, "Use python pickles instead."
def GetLastIndex(tag, hashid):
raise DeprecatedIDCError, "Use python pickles instead."
def DeleteArray(array_id):
"""
Delete array, by its ID.
def GetNextIndex(tag, hashid, idx):
raise DeprecatedIDCError, "Use python pickles instead."
@param array_id: The ID of the array to delete.
"""
__GetArrayById(array_id).kill()
def GetPrevIndex(tag, hashid, idx):
raise DeprecatedIDCError, "Use python pickles instead."
def SetHashLong(hashid, idx, value):
raise DeprecatedIDCError, "Use python pickles instead."
def SetArrayLong(array_id, idx, value):
"""
Sets the long value of an array element.
def SetHashString(hashid, idx, value):
raise DeprecatedIDCError, "Use python pickles instead."
@param array_id: The array ID.
@param idx: Index of an element.
@param value: 32bit or 64bit value to store in the array
def GetHashLong(hashid, idx):
raise DeprecatedIDCError, "Use python pickles instead."
@return: 1 in case of success, 0 otherwise
"""
return __GetArrayById(array_id).altset(idx, value)
def GetHashString(hashid, idx):
raise DeprecatedIDCError, "Use python pickles instead."
def DelHashElement(hashid, idx):
raise DeprecatedIDCError, "Use python pickles instead."
def SetArrayString(array_id, idx, value):
"""
Sets the string value of an array element.
def GetFirstHashKey(hashid):
raise DeprecatedIDCError, "Use python pickles instead."
@param array_id: The array ID.
@param idx: Index of an element.
@param value: String value to store in the array
def GetNextHashKey(hashid, idx):
raise DeprecatedIDCError, "Use python pickles instead."
@return: 1 in case of success, 0 otherwise
"""
return __GetArrayById(array_id).supset(idx, value)
def GetArrayElement(tag, array_id, idx):
"""
Get value of array element.
@param tag: Tag of array, specifies one of two array types: AR_LONG, AR_STR
@param array_id: The array ID.
@param idx: Index of an element.
@return: Value of the specified array element. Note that
this function may return char or long result. Unexistent
array elements give zero as a result.
"""
node = __GetArrayById(array_id)
if tag == AR_LONG:
return node.altval(idx, tag)
elif tag == AR_STR:
res = node.supval(idx, tag)
return 0 if res is None else res
else:
return 0
def DelArrayElement(tag, array_id, idx):
"""
Delete an array element.
@param tag: Tag of array, specifies one of two array types: AR_LONG, AR_STR
@param array_id: The array ID.
@param idx: Index of an element.
@return: 1 in case of success, 0 otherwise.
"""
node = __GetArrayById(array_id)
if tag == AR_LONG:
return node.altdel(idx, tag)
elif tag == AR_STR:
return node.supdel(idx, tag)
else:
return 0
def GetFirstIndex(tag, array_id):
"""
Get index of the first existing array element.
@param tag: Tag of array, specifies one of two array types: AR_LONG, AR_STR
@param array_id: The array ID.
@return: -1 if the array is empty, otherwise index of first array
element of given type.
"""
node = __GetArrayById(array_id)
if tag == AR_LONG:
return __l2m1(node.alt1st(tag))
elif tag == AR_STR:
return __l2m1(node.sup1st(tag))
else:
return -1
def GetLastIndex(tag, array_id):
"""
Get index of last existing array element.
@param tag: Tag of array, specifies one of two array types: AR_LONG, AR_STR
@param array_id: The array ID.
@return: -1 if the array is empty, otherwise index of first array
element of given type.
"""
node = __GetArrayById(array_id)
if tag == AR_LONG:
return __l2m1(node.altlast(tag))
elif tag == AR_STR:
return __l2m1(node.suplast(tag))
else:
return -1
def GetNextIndex(tag, array_id, idx):
"""
Get index of the next existing array element.
@param tag: Tag of array, specifies one of two array types: AR_LONG, AR_STR
@param array_id: The array ID.
@param idx: Index of the current element.
@return: -1 if no more elements, otherwise returns index of the
next array element of given type.
"""
node = __GetArrayById(array_id)
try:
if tag == AR_LONG:
return __l2m1(node.altnxt(idx, tag))
elif tag == AR_STR:
return __l2m1(node.supnxt(idx, tag))
else:
return -1
except OverflowError:
# typically: An index of -1 was passed.
return -1
def GetPrevIndex(tag, array_id, idx):
"""
Get index of the previous existing array element.
@param tag: Tag of array, specifies one of two array types: AR_LONG, AR_STR
@param array_id: The array ID.
@param idx: Index of the current element.
@return: -1 if no more elements, otherwise returns index of the
previous array element of given type.
"""
node = __GetArrayById(array_id)
try:
if tag == AR_LONG:
return __l2m1(node.altprev(idx, tag))
elif tag == AR_STR:
return __l2m1(node.supprev(idx, tag))
else:
return -1
except OverflowError:
# typically: An index of -1 was passed.
return -1
# -------------------- hashes -----------------------
def SetHashLong(hash_id, key, value):
"""
Sets the long value of a hash element.
@param hash_id: The hash ID.
@param key: Key of an element.
@param value: 32bit or 64bit value to store in the hash
@return: 1 in case of success, 0 otherwise
"""
return __GetArrayById(hash_id).hashset_idx(key, value)
def GetHashLong(hash_id, key):
"""
Gets the long value of a hash element.
@param hash_id: The hash ID.
@param key: Key of an element.
@return: the 32bit or 64bit value of the element, or 0 if no such
element.
"""
return __GetArrayById(hash_id).hashval_long(key);
def SetHashString(hash_id, key, value):
"""
Sets the string value of a hash element.
@param hash_id: The hash ID.
@param key: Key of an element.
@param value: string value to store in the hash
@return: 1 in case of success, 0 otherwise
"""
return __GetArrayById(hash_id).hashset_buf(key, value)
def GetHashString(hash_id, key):
"""
Gets the string value of a hash element.
@param hash_id: The hash ID.
@param key: Key of an element.
@return: the string value of the element, or None if no such
element.
"""
return __GetArrayById(hash_id).hashstr_buf(key);
def DelHashElement(hash_id, key):
"""
Delete a hash element.
@param hash_id: The hash ID.
@param key: Key of an element
@return: 1 upon success, 0 otherwise.
"""
return __GetArrayById(hash_id).hashdel(key)
def GetFirstHashKey(hash_id):
"""
Get the first key in the hash.
@param hash_id: The hash ID.
@return: the key, 0 otherwise.
"""
r = __GetArrayById(hash_id).hash1st()
return 0 if r is None else r
def GetLastHashKey(hash_id):
"""
Get the last key in the hash.
@param hash_id: The hash ID.
@return: the key, 0 otherwise.
"""
r = __GetArrayById(hash_id).hashlast()
return 0 if r is None else r
def GetNextHashKey(hash_id, key):
"""
Get the next key in the hash.
@param hash_id: The hash ID.
@param key: The current key.
@return: the next key, 0 otherwise
"""
r = __GetArrayById(hash_id).hashnxt(key)
return 0 if r is None else r
def GetPrevHashKey(hash_id, key):
"""
Get the previous key in the hash.
@param hash_id: The hash ID.
@param key: The current key.
@return: the previous key, 0 otherwise
"""
r = __GetArrayById(hash_id).hashprev(key)
return 0 if r is None else r
def GetLastHashKey(hashid):
raise DeprecatedIDCError, "Use python pickles instead."
def GetPrevHashKey(hashid, idx):
raise DeprecatedIDCError, "Use python pickles instead."
#----------------------------------------------------------------------------
@ -7053,6 +7413,20 @@ EXCDLG_ALWAYS = 0x00006000 # always display
DOPT_LOAD_DINFO = 0x00008000 # automatically load debug files (pdb)
def GetDebuggerEventCondition():
"""
Return the debugger event condition
"""
return idaapi.get_debugger_event_cond()
def SetDebuggerEventCondition(cond):
"""
Set the debugger event condition
"""
return idaapi.set_debugger_event_cond(cond)
def SetRemoteDebugger(hostname, password, portnum):
"""
Set remote debugging options
@ -7628,10 +8002,11 @@ def DelConst(constid, v, mask): return DelConstEx(constid, v, 0, mask)
def GetConst(constid, v, mask): return GetConstEx(constid, v, 0, mask)
def AnalyseArea(sEA, eEA): return AnalyzeArea(sEA,eEA)
def MakeStruct(ea, name): return MakeStructEx(ea, -1, name)
def Name(ea): return NameEx(BADADDR, ea)
def GetTrueName(ea): return GetTrueNameEx(BADADDR, ea)
def MakeName(ea, name): return MakeNameEx(ea,name,SN_CHECK)
def MakeStruct(ea, name): return MakeStructEx(ea, -1, name)
def MakeCustomData(ea, size, dtid, fid): return MakeCustomDataEx(ea, size, dtid, fid)
def Name(ea): return NameEx(BADADDR, ea)
def GetTrueName(ea): return GetTrueNameEx(BADADDR, ea)
def MakeName(ea, name): return MakeNameEx(ea,name,SN_CHECK)
#def GetFrame(ea): return GetFunctionAttr(ea, FUNCATTR_FRAME)
#def GetFrameLvarSize(ea): return GetFunctionAttr(ea, FUNCATTR_FRSIZE)

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
# -----------------------------------------------------------------------
# IDAPython - Python plugin for Interactive Disassembler Pro
# IDAPython - Python plugin for Interactive Disassembler
#
# Copyright (c) The IDAPython Team <idapython@googlegroups.com>
#
@ -94,7 +94,7 @@ from idautils import *
import idaapi
# Load the users personal init file
userrc = get_user_idadir() + os.sep + "idapythonrc.py"
userrc = os.path.join(get_user_idadir(), "idapythonrc.py")
if os.path.exists(userrc):
idaapi.IDAPython_ExecScript(userrc, globals())

View File

@ -23,11 +23,14 @@
#define PY_SFMT64 "l"
#endif
//------------------------------------------------------------------------
#define S_IDAAPI_MODNAME "idaapi"
#define S_IDC_MODNAME "idc"
#define S_IDAAPI_EXECSCRIPT "IDAPython_ExecScript"
#define S_IDAAPI_COMPLETION "IDAPython_Completion"
#define S_IDAAPI_FORMATEXC "IDAPython_FormatExc"
//------------------------------------------------------------------------
// Vector of PyObject*
typedef qvector<PyObject *> ppyobject_vec_t;
@ -57,6 +60,36 @@ typedef qvector<PyObject *> ppyobject_vec_t;
#define CIP_OK 1 // Success
#define CIP_OK_NODECREF 2 // Success but do not decrement its reference
//---------------------------------------------------------------------------
// Helper macro to create C counterparts of Python py_clinked_object_t object
#ifdef __PYWRAPS__
#define DECLARE_PY_CLINKED_OBJECT(type) \
static PyObject *type##_create() \
{ \
return PyCObject_FromVoidPtr(new type(), NULL); \
} \
static bool type##_destroy(PyObject *py_obj) \
{ \
if ( !PyCObject_Check(py_obj) ) \
return false; \
delete (type *)PyCObject_AsVoidPtr(py_obj); \
return true; \
} \
static type *type##_get_clink(PyObject *self) \
{ \
return (type *)pyobj_get_clink(self); \
} \
static PyObject *type##_get_clink_ptr(PyObject *self) \
{ \
return PyLong_FromUnsignedLongLong( \
(unsigned PY_LONG_LONG)pyobj_get_clink(self)); \
}
#else
// SWIG does not expand macros and thus those definitions won't be wrapped
// Use DECLARE_PY_CLINKED_OBJECT(type) inside the .i file
#define DECLARE_PY_CLINKED_OBJECT(type)
#endif // __PYWRAPS__
//---------------------------------------------------------------------------
class CGilStateAuto
{
@ -82,11 +115,18 @@ public:
#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
insn_t *insn_t_get_clink(PyObject *self);
op_t *op_t_get_clink(PyObject *self);
// Returns a reference to a class
PyObject *get_idaapi_attr(const char *attr);
// Returns a reference to a class by its ID
PyObject *get_idaapi_attr_by_id(const int class_id);
// Tries to import a module and swallows the exception if it fails and returns NULL
PyObject *PyW_TryImportModule(const char *name);
@ -112,7 +152,8 @@ bool PyW_GetNumber(PyObject *py_var, uint64 *num, bool *is_64 = NULL);
bool PyW_IsSequenceType(PyObject *obj);
// Returns an error string from the last exception (and clears it)
bool PyW_GetError(qstring *out = NULL);
bool PyW_GetError(qstring *out = NULL, bool clear_err = true);
bool PyW_GetError(char *buf, size_t bufsz, bool clear_err = true);
// If an error occured (it calls PyGetError) it displays it and return TRUE
// This function is used when calling callbacks
@ -124,10 +165,6 @@ PyObject *create_idaapi_class_instance0(const char *clsname);
// Utility function to create linked class instances
PyObject *create_idaapi_linked_class_instance(const char *clsname, void *lnk);
// [De]Initializes PyWraps
bool init_pywraps();
void deinit_pywraps();
// Returns the string representation of a PyObject
bool PyW_ObjectToString(PyObject *obj, qstring *out);
@ -135,6 +172,24 @@ bool PyW_ObjectToString(PyObject *obj, qstring *out);
// and sets a python exception on failure.
bool convert_pyobj_to_idc_exc(PyObject *py_obj, idc_value_t *idc_obj);
// Creates and initializes an IDC exception
error_t PyW_CreateIdcException(idc_value_t *res, const char *msg);
//
// Conversion functions
//
bool pyw_convert_idc_args(
const idc_value_t args[],
int nargs,
ppyobject_vec_t &pargs,
boolvec_t *decref,
char *errbuf = NULL,
size_t errbufsize = 0);
void pyw_free_idc_args(
ppyobject_vec_t &pargs,
boolvec_t *decref = NULL);
// Converts Python variable to IDC variable
// gvar_sn is used in case the Python object was a created from a call to idcvar_to_pyvar and the IDC object was a VT_REF
int pyvar_to_idcvar(
@ -160,17 +215,22 @@ PyObject *PyW_IntVecToPyList(const intvec_t &intvec);
// Converts an Python list to an intvec
bool PyW_PyListToIntVec(PyObject *py_list, intvec_t &intvec);
// Returns a reference to a class
PyObject *get_idaapi_attr(const char *attr);
// Returns a reference to a class by its ID
PyObject *get_idaapi_attr_by_id(const int class_id);
// Converts a Python list to a qstrvec
bool PyW_PyListToStrVec(PyObject *py_list, qstrvec_t &strvec);
//---------------------------------------------------------------------------
//
// notify_when()
//
bool pywraps_nw_term();
bool pywraps_nw_notify(int slot, ...);
bool pywraps_nw_init();
//---------------------------------------------------------------------------
const char *pywraps_check_autoscripts();
// [De]Initializes PyWraps
bool init_pywraps();
void deinit_pywraps();
#endif

View File

@ -13,6 +13,7 @@
%ignore adjust_visea;
%ignore prev_visea;
%ignore next_visea;
%ignore visit_patched_bytes;
%ignore is_first_visea;
%ignore is_last_visea;
%ignore is_visible_finally;
@ -36,7 +37,6 @@
%ignore noExtra;
%ignore coagulate;
%ignore coagulate_dref;
%ignore get_item_head;
%ignore init_hidden_areas;
%ignore save_hidden_areas;
%ignore term_hidden_areas;
@ -74,6 +74,7 @@
%ignore register_custom_data_type;
%ignore get_many_bytes;
%ignore get_ascii_contents;
%ignore get_ascii_contents2;
// TODO: This could be fixed (if needed)
%ignore set_dbgmem_source;
@ -86,6 +87,7 @@
%clear(void *buf, ssize_t size);
%clear(opinfo_t *);
%rename (visit_patched_bytes) py_visit_patched_bytes;
%rename (nextthat) py_nextthat;
%rename (prevthat) py_prevthat;
%rename (get_custom_data_type) py_get_custom_data_type;
@ -95,7 +97,7 @@
%rename (unregister_custom_data_type) py_unregister_custom_data_type;
%rename (register_custom_data_type) py_register_custom_data_type;
%rename (get_many_bytes) py_get_many_bytes;
%rename (get_ascii_contents) py_get_ascii_contents;
%rename (get_ascii_contents2) py_get_ascii_contents2;
%{
//<code(py_bytes)>
//------------------------------------------------------------------------
@ -121,6 +123,30 @@ static ea_t py_npthat(ea_t ea, ea_t bound, PyObject *py_callable, bool next)
return (next ? nextthat : prevthat)(ea, bound, py_testf_cb, py_callable);
}
//---------------------------------------------------------------------------
static int idaapi py_visit_patched_bytes_cb(
ea_t ea,
int32 fpos,
uint32 o,
uint32 v,
void *ud)
{
PYW_GIL_ENSURE;
PyObject *py_result = PyObject_CallFunction(
(PyObject *)ud,
PY_FMT64 "iII",
pyul_t(ea),
fpos,
o,
v);
PYW_GIL_RELEASE;
PyW_ShowCbErr("visit_patched_bytes");
int ret = (py_result != NULL && PyInt_Check(py_result)) ? PyInt_AsLong(py_result) : 0;
Py_XDECREF(py_result);
return ret;
}
//------------------------------------------------------------------------
@ -639,11 +665,54 @@ static PyObject *py_data_format_to_py_dict(const data_format_t *df)
//<inline(py_bytes)>
//------------------------------------------------------------------------
/*
#<pydoc>
def visit_patched_bytes(ea1, ea2, callable):
"""
Enumerates patched bytes in the given range and invokes a callable
@param ea1: start address
@param ea2: end address
@param callable: a Python callable with the following prototype:
callable(ea, fpos, org_val, patch_val).
If the callable returns non-zero then that value will be
returned to the caller and the enumeration will be
interrupted.
@return: Zero if the enumeration was successful or the return
value of the callback if enumeration was interrupted.
"""
pass
#</pydoc>
*/
static int py_visit_patched_bytes(ea_t ea1, ea_t ea2, PyObject *py_callable)
{
if ( !PyCallable_Check(py_callable) )
return 0;
else
return visit_patched_bytes(ea1, ea2, py_visit_patched_bytes_cb, py_callable);
}
//------------------------------------------------------------------------
/*
#<pydoc>
def nextthat(ea, maxea, callable):
"""
Find next address with a flag satisfying the function 'testf'.
Start searching from address 'ea'+1 and inspect bytes up to 'maxea'.
maxea is not included in the search range.
@param callable: a Python callable with the following prototype:
callable(flags). Return True to stop enumeration.
@return: the found address or BADADDR.
"""
pass
#</pydoc>
*/
static ea_t py_nextthat(ea_t ea, ea_t maxea, PyObject *callable)
{
return py_npthat(ea, maxea, callable, true);
}
//---------------------------------------------------------------------------
static ea_t py_prevthat(ea_t ea, ea_t minea, PyObject *callable)
{
return py_npthat(ea, minea, callable, false);
@ -694,37 +763,40 @@ static PyObject *py_get_many_bytes(ea_t ea, unsigned int size)
//---------------------------------------------------------------------------
/*
#<pydoc>
def get_ascii_contents(ea, len, type, bufsize):
def get_ascii_contents2(ea, len, type, flags = ACFOPT_ASCII):
"""
Get contents of ascii string
This function returns the displayed part of the string
It works even if the string has not been created in the database yet.
@param ea: linear address of the string
@param len: length of the string in bytes
@param len: length of the string in bytes (including terminating 0)
@param type: type of the string
@param bufsize: size of output buffer
@return: 1-ok, 0-ascii string is too long and was truncated
@param flags: combination of ACFOPT_...
@return: string contents (not including terminating 0) or None
"""
pass
#</pydoc>
*/
static PyObject *py_get_ascii_contents(
static PyObject *py_get_ascii_contents2(
ea_t ea,
size_t len,
int32 type,
size_t bufsize = MAXSTR)
int flags = ACFOPT_ASCII)
{
char *buf = (char *)qalloc(bufsize);
char *buf = (char *)qalloc(len+1);
if ( buf == NULL )
return NULL;
if ( !get_ascii_contents(ea, len, type, buf, bufsize) )
size_t used_size;
if ( !get_ascii_contents2(ea, len, type, buf, len+1, &used_size) )
{
qfree(buf);
Py_RETURN_NONE;
}
PyObject *py_buf = PyString_FromStringAndSize((const char *)buf, bufsize);
if ( type == ASCSTR_C && used_size > 0 && buf[used_size-1] == '\0' )
used_size--;
PyObject *py_buf = PyString_FromStringAndSize((const char *)buf, used_size);
qfree(buf);
return py_buf;
}

View File

@ -114,86 +114,81 @@ static PyObject *refresh_debugger_memory()
Py_RETURN_NONE;
}
//</inline(py_dbg)>
int idaapi DBG_Callback(void *ud, int notification_code, va_list va);
class DBG_Hooks
{
public:
virtual ~DBG_Hooks() {};
virtual ~DBG_Hooks() {};
bool hook() { return hook_to_notification_point(HT_DBG, DBG_Callback, this); };
bool unhook() { return unhook_from_notification_point(HT_DBG, DBG_Callback, this); };
/* Hook functions to be overridden in Python */
virtual void dbg_process_start(pid_t pid,
thid_t tid,
ea_t ea,
char *name,
ea_t base,
asize_t size) { };
virtual void dbg_process_exit(pid_t pid,
thid_t tid,
ea_t ea,
int exit_code) { };
virtual void dbg_process_attach(pid_t pid,
thid_t tid,
ea_t ea,
char *name,
ea_t base,
asize_t size) { };
virtual void dbg_process_detach(pid_t pid,
thid_t tid,
ea_t ea) { };
virtual void dbg_thread_start(pid_t pid,
thid_t tid,
ea_t ea) { };
virtual void dbg_thread_exit(pid_t pid,
thid_t tid,
ea_t ea,
int exit_code) { };
virtual void dbg_library_load(pid_t pid,
thid_t tid,
ea_t ea,
char *name,
ea_t base,
asize_t size) { };
virtual void dbg_library_unload(pid_t pid,
thid_t tid,
ea_t ea,
char *libname) { };
virtual void dbg_information(pid_t pid,
thid_t tid,
ea_t ea,
char *info) { };
virtual int dbg_exception(pid_t pid,
thid_t tid,
ea_t ea,
int code,
bool can_cont,
ea_t exc_ea,
char *info) { return 0; };
virtual void dbg_suspend_process(void) { };
virtual int dbg_bpt(thid_t tid, ea_t breakpoint_ea) { return 0; };
virtual int dbg_trace(thid_t tid, ea_t ip) { return 0; };
virtual void dbg_request_error(int failed_command,
int failed_dbg_notification) { };
virtual void dbg_step_into(void) { };
virtual void dbg_step_over(void) { };
virtual void dbg_run_to(thid_t tid) { };
virtual void dbg_step_until_ret(void) { };
bool hook() { return hook_to_notification_point(HT_DBG, DBG_Callback, this); };
bool unhook() { return unhook_from_notification_point(HT_DBG, DBG_Callback, this); };
/* Hook functions to be overridden in Python */
virtual void dbg_process_start(pid_t pid,
thid_t tid,
ea_t ea,
char *name,
ea_t base,
asize_t size) { };
virtual void dbg_process_exit(pid_t pid,
thid_t tid,
ea_t ea,
int exit_code) { };
virtual void dbg_process_attach(pid_t pid,
thid_t tid,
ea_t ea,
char *name,
ea_t base,
asize_t size) { };
virtual void dbg_process_detach(pid_t pid,
thid_t tid,
ea_t ea) { };
virtual void dbg_thread_start(pid_t pid,
thid_t tid,
ea_t ea) { };
virtual void dbg_thread_exit(pid_t pid,
thid_t tid,
ea_t ea,
int exit_code) { };
virtual void dbg_library_load(pid_t pid,
thid_t tid,
ea_t ea,
char *name,
ea_t base,
asize_t size) { };
virtual void dbg_library_unload(pid_t pid,
thid_t tid,
ea_t ea,
char *libname) { };
virtual void dbg_information(pid_t pid,
thid_t tid,
ea_t ea,
char *info) { };
virtual int dbg_exception(pid_t pid,
thid_t tid,
ea_t ea,
int code,
bool can_cont,
ea_t exc_ea,
char *info) { return 0; };
virtual void dbg_suspend_process(void) { };
virtual int dbg_bpt(thid_t tid, ea_t breakpoint_ea) { return 0; };
virtual int dbg_trace(thid_t tid, ea_t ip) { return 0; };
virtual void dbg_request_error(int failed_command,
int failed_dbg_notification) { };
virtual void dbg_step_into(void) { };
virtual void dbg_step_over(void) { };
virtual void dbg_run_to(pid_t pid, thid_t tid, ea_t ea) { };
virtual void dbg_step_until_ret(void) { };
};
int idaapi DBG_Callback(void *ud, int notification_code, va_list va)
{
class DBG_Hooks *proxy = (class DBG_Hooks *)ud;
debug_event_t *event;
thid_t tid;
int *warn;
ea_t ip;
ea_t breakpoint_ea;
try {
int code = 0;
try
{
switch (notification_code)
{
case dbg_process_start:
@ -204,135 +199,155 @@ int idaapi DBG_Callback(void *ud, int notification_code, va_list va)
event->modinfo.name,
event->modinfo.base,
event->modinfo.size);
return 0;
break;
case dbg_process_exit:
event = va_arg(va, debug_event_t *);
proxy->dbg_process_exit(event->pid,
proxy->dbg_process_exit(
event->pid,
event->tid,
event->ea,
event->exit_code);
return 0;
break;
case dbg_process_attach:
event = va_arg(va, debug_event_t *);
proxy->dbg_process_attach(event->pid,
proxy->dbg_process_attach(
event->pid,
event->tid,
event->ea,
event->modinfo.name,
event->modinfo.base,
event->modinfo.size);
return 0;
break;
case dbg_process_detach:
event = va_arg(va, debug_event_t *);
proxy->dbg_process_detach(event->pid,
proxy->dbg_process_detach(
event->pid,
event->tid,
event->ea);
return 0;
break;
case dbg_thread_start:
event = va_arg(va, debug_event_t *);
proxy->dbg_thread_start(event->pid,
proxy->dbg_thread_start(
event->pid,
event->tid,
event->ea);
return 0;
break;
case dbg_thread_exit:
event = va_arg(va, debug_event_t *);
proxy->dbg_thread_exit(event->pid,
proxy->dbg_thread_exit(
event->pid,
event->tid,
event->ea,
event->exit_code);
return 0;
break;
case dbg_library_load:
event = va_arg(va, debug_event_t *);
proxy->dbg_library_load(event->pid,
proxy->dbg_library_load(
event->pid,
event->tid,
event->ea,
event->modinfo.name,
event->modinfo.base,
event->modinfo.size);
return 0;
break;
case dbg_library_unload:
event = va_arg(va, debug_event_t *);
proxy->dbg_library_unload(event->pid,
proxy->dbg_library_unload(
event->pid,
event->tid,
event->ea,
event->info);
return 0;
break;
case dbg_information:
event = va_arg(va, debug_event_t *);
proxy->dbg_information(event->pid,
proxy->dbg_information(
event->pid,
event->tid,
event->ea,
event->info);
return 0;
break;
case dbg_exception:
{
event = va_arg(va, debug_event_t *);
warn = va_arg(va, int *);
*warn = proxy->dbg_exception(event->pid,
int *warn = va_arg(va, int *);
*warn = proxy->dbg_exception(
event->pid,
event->tid,
event->ea,
event->exc.code,
event->exc.can_cont,
event->exc.ea,
event->exc.info);
return 0;
break;
}
case dbg_suspend_process:
proxy->dbg_suspend_process();
return 0;
break;
case dbg_bpt:
tid = va_arg(va, thid_t);
breakpoint_ea = va_arg(va, ea_t);
warn = va_arg(va, int *);
{
thid_t tid = va_arg(va, thid_t);
ea_t breakpoint_ea = va_arg(va, ea_t);
int *warn = va_arg(va, int *);
*warn = proxy->dbg_bpt(tid, breakpoint_ea);
return 0;
break;
}
case dbg_trace:
tid = va_arg(va, thid_t);
ip = va_arg(va, ea_t);
return proxy->dbg_trace(tid, ip);
{
thid_t tid = va_arg(va, thid_t);
ea_t ip = va_arg(va, ea_t);
code = proxy->dbg_trace(tid, ip);
break;
}
case dbg_request_error:
{
int failed_command = (int)va_argi(va, ui_notification_t);
int failed_dbg_notification = (int)va_argi(va, dbg_notification_t);
proxy->dbg_request_error(failed_command, failed_dbg_notification);
return 0;
break;
}
case dbg_step_into:
proxy->dbg_step_into();
return 0;
break;
case dbg_step_over:
proxy->dbg_step_over();
return 0;
break;
case dbg_run_to:
tid = va_arg(va, thid_t);
proxy->dbg_run_to(tid);
return 0;
event = va_arg(va, debug_event_t *);
proxy->dbg_run_to(
event->pid,
event->tid,
event->ea);
break;
case dbg_step_until_ret:
proxy->dbg_step_until_ret();
return 0;
break;
}
}
catch (Swig::DirectorException &)
catch (Swig::DirectorException &e)
{
msg("Exception in DBG Hook function:\n");
msg("Exception in DBG Hook function: %s\n", e.getMessage());
if (PyErr_Occurred())
{
PyErr_Print();
}
}
return 0;
return code;
}
//</inline(py_dbg)>
%}

View File

@ -12,6 +12,7 @@
%ignore free_ioports;
%ignore lread;
%ignore qlread;
%ignore efilelength;
%ignore qlgets;
%ignore qlgetc;
%ignore lreadbytes;

View File

@ -7,7 +7,12 @@
%ignore register_extlang;
%ignore IDCFuncs;
%ignore set_idc_func;
%ignore set_idc_dtor;
%ignore set_idc_method;
%ignore set_idc_getattr;
%ignore set_idc_setattr;
%ignore set_idc_func_ex;
%ignore run_statements_idc;
%ignore VarLong;
%ignore VarNum;
%ignore extlang_get_attr_exists;
@ -46,54 +51,291 @@
%ignore idc_resolve_label;
%ignore idc_resolver_ea;
%ignore setup_lowcnd_regfuncs;
%cstring_output_maxstr_none(char *errbuf, size_t errbufsize);
/* Compile* functions return false when error so the return */
/* value must be negated for the error string to be returned */
%ignore CompileEx;
%rename (CompileEx) CompileEx_wrap;
%inline %{
bool CompileEx_wrap(const char *file, bool del_macros,
char *errbuf, size_t errbufsize)
{
return !CompileEx(file, del_macros, errbuf, errbufsize);
}
%}
%ignore Compile;
%rename (Compile) Compile_wrap;
%inline %{
bool Compile_wrap(const char *file, char *errbuf, size_t errbufsize)
{
return !Compile(file, errbuf, errbufsize);
}
%}
%ignore calcexpr;
%rename (calcexpr) calcexpr_wrap;
%inline %{
bool calcexpr_wrap(ea_t where,const char *line, idc_value_t *rv, char *errbuf, size_t errbufsize)
{
return !calcexpr(where, line, rv, errbuf, errbufsize);
}
%}
%ignore calc_idc_expr;
%rename (calc_idc_expr) calc_idc_expr_wrap;
%inline %{
bool calc_idc_expr_wrap(ea_t where,const char *line, idc_value_t *rv, char *errbuf, size_t errbufsize)
{
return !calc_idc_expr(where, line, rv, errbuf, errbufsize);
}
%}
%ignore CompileLine(const char *line, char *errbuf, size_t errbufsize, uval_t (idaapi*_getname)(const char *name)=NULL);
%ignore CompileLineEx;
%ignore CompileLine;
%rename (CompileLine) CompileLine_wrap;
%{
//<code(py_expr)>
struct py_idcfunc_ctx_t
{
PyObject *py_func;
qstring name;
int nargs;
py_idcfunc_ctx_t(PyObject *py_func, const char *name, int nargs): py_func(py_func), name(name), nargs(nargs)
{
Py_INCREF(py_func);
}
~py_idcfunc_ctx_t()
{
Py_DECREF(py_func);
}
};
//---------------------------------------------------------------------------
static error_t py_call_idc_func(
void *_ctx,
idc_value_t *argv,
idc_value_t *r)
{
// Convert IDC arguments to Python list
py_idcfunc_ctx_t *ctx = (py_idcfunc_ctx_t *)_ctx;
int cvt;
ppyobject_vec_t pargs;
char errbuf[MAXSTR];
if ( !pyw_convert_idc_args(argv, ctx->nargs, pargs, NULL, errbuf, sizeof(errbuf)) )
{
// Error during conversion? Create an IDC exception
return PyW_CreateIdcException(r, errbuf);
}
// Call the Python function
PYW_GIL_ENSURE;
PyObject *py_result = PyObject_CallObject(
ctx->py_func,
pargs.empty() ? NULL : pargs[0]);
error_t err;
if ( PyW_GetError(errbuf, sizeof(errbuf)) )
{
err = PyW_CreateIdcException(r, errbuf);
Py_XDECREF(py_result);
}
else
{
// Convert the result to IDC
r->clear();
cvt = pyvar_to_idcvar(py_result, r);
if ( cvt < CIP_OK )
err = PyW_CreateIdcException(r, "ERROR: bad return value");
else
err = eOk;
if ( cvt != CIP_OK_NODECREF )
Py_XDECREF(py_result);
}
PYW_GIL_RELEASE;
// Free the converted args
pyw_free_idc_args(pargs);
return err;
}
//</code(py_expr)>
%}
%inline %{
//<inline(py_expr)>
//---------------------------------------------------------------------------
static size_t py_get_call_idc_func()
{
return (size_t)py_call_idc_func;
}
//---------------------------------------------------------------------------
// Internal function:
// - capture the python callable
// - return a C context as a numeric value
static size_t pyw_register_idc_func(
const char *name,
const char *args,
PyObject *py_fp)
{
return (size_t)new py_idcfunc_ctx_t(py_fp, name, strlen(args));
}
//---------------------------------------------------------------------------
// Internal function:
// - free the C context
static bool pyw_unregister_idc_func(size_t ctxptr)
{
// Unregister the function
py_idcfunc_ctx_t *ctx = (py_idcfunc_ctx_t *)ctxptr;
bool ok = set_idc_func_ex(ctx->name.c_str(), NULL, NULL, 0);
// Delete the context
delete ctx;
return ok;
}
//---------------------------------------------------------------------------
static bool py_set_idc_func_ex(
const char *name,
size_t fp_ptr,
const char *args,
int flags)
{
return set_idc_func_ex(name, (idc_func_t *)fp_ptr, args, flags);
}
//---------------------------------------------------------------------------
// Compile* functions return false when error so the return
// value must be negated for the error string to be returned
bool CompileEx_wrap(
const char *file,
bool del_macros,
char *errbuf, size_t errbufsize)
{
return !CompileEx(file, del_macros, errbuf, errbufsize);
}
bool Compile_wrap(const char *file, char *errbuf, size_t errbufsize)
{
return !Compile(file, errbuf, errbufsize);
}
bool calcexpr_wrap(
ea_t where,
const char *line,
idc_value_t *rv,
char *errbuf, size_t errbufsize)
{
return !calcexpr(where, line, rv, errbuf, errbufsize);
}
bool calc_idc_expr_wrap(
ea_t where,
const char *line,
idc_value_t *rv,
char *errbuf, size_t errbufsize)
{
return !calc_idc_expr(where, line, rv, errbuf, errbufsize);
}
bool CompileLine_wrap(const char *line, char *errbuf, size_t errbufsize)
{
return !CompileLineEx(line, errbuf, errbufsize);
return !CompileLineEx(line, errbuf, errbufsize);
}
//</inline(py_expr)>
%}
%include "expr.hpp"
%pythoncode %{
#<pycode(py_expr)>
try:
import types
import ctypes
# Callback for IDC func callback (On Windows, we use stdcall)
# typedef error_t idaapi idc_func_t(idc_value_t *argv,idc_value_t *r);
_IDCFUNC_CB_T = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p)
# A trampoline function that is called from idcfunc_t that will
# call the Python callback with the argv and r properly serialized to python
call_idc_func__ = ctypes.CFUNCTYPE(ctypes.c_long)(_idaapi.py_get_call_idc_func())
except:
def call_idc_func__(*args):
warning("IDC extensions need ctypes library in order to work")
return 0
try:
_IDCFUNC_CB_T = CFUNCTYPE(c_int, c_void_p, c_void_p)
except:
_IDCFUNC_CB_T = None
# --------------------------------------------------------------------------
EXTFUN_BASE = 0x0001
"""requires open database"""
EXTFUN_NORET = 0x0002
"""does not return. the interpreter may clean up its state before calling it."""
EXTFUN_SAFE = 0x0004
"""thread safe function. may be called"""
# --------------------------------------------------------------------------
class _IdcFunction(object):
"""
Internal class that calls pyw_call_idc_func() with a context
"""
def __init__(self, ctxptr):
self.ctxptr = ctxptr
# Take a reference to the ctypes callback
# (note: this will create a circular reference)
self.cb = _IDCFUNC_CB_T(self)
fp_ptr = property(lambda self: ctypes.cast(self.cb, ctypes.c_void_p).value)
def __call__(self, args, res):
return call_idc_func__(self.ctxptr, args, res)
# --------------------------------------------------------------------------
# Dictionary to remember IDC function names along with the context pointer
# retrieved by using the internal pyw_register_idc_func()
__IDC_FUNC_CTXS = {}
# --------------------------------------------------------------------------
def set_idc_func_ex(name, fp=None, args=(), flags=0):
"""
Extends the IDC language by exposing a new IDC function that is backed up by a Python function
This function also unregisters the IDC function if 'fp' was passed as None
@param name: IDC function name to expose
@param fp: Python callable that will receive the arguments and return a tuple.
If this argument is None then the IDC function is unregistered
@param args: Arguments. A tuple of idaapi.VT_XXX constants
@param flags: IDC function flags. A combination of EXTFUN_XXX constants
@return: Boolean.
"""
global __IDC_FUNC_CTXS
# Get the context
f = __IDC_FUNC_CTXS.get(name, None)
# Unregistering?
if fp is None:
# Not registered?
if f is None:
return False
# Break circular reference
del f.cb
# Delete the name from the dictionary
del __IDC_FUNC_CTXS[name]
# Delete the context and unregister the function
return _idaapi.pyw_unregister_idc_func(f.ctxptr)
# Registering a function that is already registered?
if f is not None:
# Unregister it first
set_idc_func_ex(name, None)
# Convert the tupple argument info to a string
args = "".join([chr(x) for x in args])
# Create a context
ctxptr = _idaapi.pyw_register_idc_func(name, args, fp)
if ctxptr == 0:
return False
# Bind the context with the IdcFunc object
f = _IdcFunction(ctxptr)
# Remember the Python context
__IDC_FUNC_CTXS[name] = f
# Register IDC function with a callback
return _idaapi.py_set_idc_func_ex(
name,
f.fp_ptr,
args,
flags)
#</pycode(py_expr)>
%}

View File

@ -26,7 +26,7 @@ private:
nodetext_cache_t(const char *t, bgcolor_t c): text(t), bgcolor(c) { }
nodetext_cache_t() { }
};
class nodetext_cache_map_t: public std::map<int, nodetext_cache_t>
{
public:
@ -62,24 +62,24 @@ private:
private:
Py_ssize_t uid;
public:
cmdid_map_t()
{
// We start by one and keep zero for error id
uid = 1;
uid = 1;
}
void add(py_graph_t *pyg)
{
(*this)[uid] = pyg;
++uid;
}
const Py_ssize_t id() const
{
const Py_ssize_t id() const
{
return uid;
}
void clear(py_graph_t *pyg)
{
iterator e = end();
@ -94,7 +94,7 @@ private:
++it;
}
}
py_graph_t *get(Py_ssize_t id)
{
iterator it = find(id);
@ -123,7 +123,7 @@ private:
py_graph_t *_this = cmdid_pyg.get(id);
if ( _this != NULL )
_this->on_command(id);
return true;
}
@ -208,11 +208,11 @@ private:
edge_ids[j] = v;
}
// Incomplete?
if ( j != qnumber(edge_ids) )
break;
// Add the edge
g->add_edge(edge_ids[0], edge_ids[1], NULL);
}
@ -312,27 +312,27 @@ private:
PYW_GIL_ENSURE;
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_CLOSE, NULL);
PYW_GIL_RELEASE;
Py_XDECREF(result);
}
unbind();
}
// Remove the TForm from list
if ( form != NULL )
tform_pyg.erase(form);
// Remove all associated commands from the list
cmdid_pyg.clear(this);
// Delete this instance
delete this;
}
// graph is being clicked
int on_clicked(
graph_viewer_t * /*gv*/,
selection_item_t * /*item1*/,
graph_viewer_t * /*gv*/,
selection_item_t * /*item1*/,
graph_item_t *item2)
{
// in: graph_viewer_t *gv
@ -349,12 +349,12 @@ private:
PYW_GIL_ENSURE;
PyObject *result = PyObject_CallMethod(
self,
(char *)S_ON_CLICK,
"i",
self,
(char *)S_ON_CLICK,
"i",
item2->n);
PYW_GIL_RELEASE;
if ( result == NULL || !PyObject_IsTrue(result) )
{
Py_XDECREF(result);
@ -376,15 +376,15 @@ private:
//selection_item_t *s = va_arg(va, selection_item_t *);
if ( item == NULL || !item->is_node )
return 1;
PYW_GIL_ENSURE;
PyObject *result = PyObject_CallMethod(
self,
(char *)S_ON_DBL_CLICK,
"i",
self,
(char *)S_ON_DBL_CLICK,
"i",
item->node);
PYW_GIL_RELEASE;
if ( result == NULL || !PyObject_IsTrue(result) )
{
Py_XDECREF(result);
@ -399,8 +399,8 @@ private:
{
PYW_GIL_ENSURE;
PyObject *result = PyObject_CallMethod(
self,
(char *)S_ON_ACTIVATE,
self,
(char *)S_ON_ACTIVATE,
NULL);
PYW_GIL_RELEASE;
Py_XDECREF(result);
@ -411,8 +411,8 @@ private:
{
PYW_GIL_ENSURE;
PyObject *result = PyObject_CallMethod(
self,
(char *)S_ON_DEACTIVATE,
self,
(char *)S_ON_DEACTIVATE,
NULL);
PYW_GIL_RELEASE;
@ -430,9 +430,9 @@ private:
PYW_GIL_ENSURE;
PyObject *result = PyObject_CallMethod(
self,
(char *)S_ON_SELECT,
"i",
self,
(char *)S_ON_SELECT,
"i",
curnode);
PYW_GIL_RELEASE;
@ -473,7 +473,7 @@ private:
else
{
// Ignore the click
ret = 1;
ret = 1;
}
break;
//
@ -491,20 +491,20 @@ private:
case grcode_gotfocus:
if ( cb_flags & GR_HAVE_GOTFOCUS )
on_gotfocus(va_arg(va, graph_viewer_t *));
ret = 0;
break;
//
case grcode_lostfocus:
if ( cb_flags & GR_HAVE_LOSTFOCUS )
on_lostfocus(va_arg(va, graph_viewer_t *));
ret = 0;
break;
//
case grcode_user_refresh:
on_user_refresh(va_arg(va, mutable_graph_t *));
ret = 1;
break;
//
@ -664,7 +664,9 @@ private:
{
// get a unique graph id
netnode id;
id.create();
char grnode[MAXSTR];
qsnprintf(grnode, sizeof(grnode), "$ pygraph %s", title);
id.create(grnode);
gv = create_graph_viewer(form, id, s_callback, this, 0);
open_tform(form, FORM_MDI | FORM_TAB | FORM_MENU);
if ( gv != NULL )
@ -724,7 +726,7 @@ private:
if ( _this == NULL || _this->form == NULL )
return;
close_tform(_this->form, 0);
close_tform(_this->form, FORM_CLOSE_LATER);
}
static void Refresh(PyObject *self)

View File

@ -1,4 +1,4 @@
%module(docstring="IDA Pro Plugin SDK API wrapper",directors="1") idaapi
%module(docstring="IDA Plugin SDK API wrapper",directors="1") idaapi
// Suppress 'previous definition of XX' warnings
#pragma SWIG nowarn=302
// and others...
@ -12,14 +12,41 @@
#pragma SWIG nowarn=451
#pragma SWIG nowarn=454 // Setting a pointer/reference variable may leak memory
%constant size_t SIZE_MAX = size_t(-1);
// Enable automatic docstring generation
%feature(autodoc);
%define SWIG_DECLARE_PY_CLINKED_OBJECT(type)
%inline %{
static PyObject *type##_create()
{
return PyCObject_FromVoidPtr(new type(), NULL);
}
static bool type##_destroy(PyObject *py_obj)
{
if ( !PyCObject_Check(py_obj) )
return false;
delete (type *)PyCObject_AsVoidPtr(py_obj);
return true;
}
static type *type##_get_clink(PyObject *self)
{
return (type *)pyobj_get_clink(self);
}
static PyObject *type##_get_clink_ptr(PyObject *self)
{
return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)pyobj_get_clink(self));
}
%}
%enddef
// We use those special maps because SWIG wraps passed PyObject* with 'SwigPtr_PyObject' and 'SwigVar_PyObject'
// They act like autoptr and decrement the reference of the object when the scope ends
// We need to keep a reference outside SWIG and let the caller manage its references
%typemap(directorin) PyObject * "/*%din%*/Py_XINCREF($1_name);$input = $1_name;"
%typemap(directorout) PyObject * "/*%dout%*/$result = result;Py_XINCREF($result);"
%{
#include <Python.h>
@ -29,7 +56,7 @@
#ifndef NO_OBSOLETE_FUNCS
#define NO_OBSOLETE_FUNCS 1
#endif
#endif
#ifdef HAVE_SSIZE_T
#define _SSIZE_T_DEFINED 1
@ -124,6 +151,7 @@ enum scfield_types_t
FT_CHRARR_STATIC,
};
//---------------------------------------------------------------------------
struct scfld_t
{
const char *field_name;
@ -524,6 +552,30 @@ bool PyW_PyListToIntVec(PyObject *py_list, intvec_t &intvec)
return pyvar_walk_list(py_list, pylist_to_intvec_cb, &intvec) != CIP_FAILED;
}
//---------------------------------------------------------------------------
static int idaapi pylist_to_strvec_cb(
PyObject *py_item,
Py_ssize_t /*index*/,
void *ud)
{
qstrvec_t &strvec = *(qstrvec_t *)ud;
const char *s;
if ( !PyString_Check(py_item) )
s = "";
else
s = PyString_AsString(py_item);
strvec.push_back(s);
return CIP_OK;
}
//---------------------------------------------------------------------------
bool PyW_PyListToStrVec(PyObject *py_list, qstrvec_t &strvec)
{
strvec.clear();
return pyvar_walk_list(py_list, pylist_to_strvec_cb, &strvec) != CIP_FAILED;
}
//-------------------------------------------------------------------------
// Checks if the given py_var is a special PyIdc_cvt_helper object.
// It does that by examining the magic attribute and returns its numeric value.
@ -874,7 +926,9 @@ int idcvar_to_pyvar(
PyObject *py_cls = get_idaapi_attr_by_id(PY_CLSID_CVT_INT64);
if ( py_cls == NULL )
return CIP_FAILED;
PYW_GIL_ENSURE;
*py_var = PyObject_CallFunctionObjArgs(py_cls, PyLong_FromLongLong(idc_var.i64), NULL);
PYW_GIL_RELEASE;
Py_DECREF(py_cls);
if ( PyW_GetError() || *py_var == NULL )
return CIP_FAILED;
@ -928,7 +982,9 @@ int idcvar_to_pyvar(
return CIP_FAILED;
// Create a byref object with None value. We populate it later
PYW_GIL_ENSURE;
*py_var = PyObject_CallFunctionObjArgs(py_cls, Py_None, NULL);
PYW_GIL_RELEASE;
Py_DECREF(py_cls);
if ( PyW_GetError() || *py_var == NULL )
return CIP_FAILED;
@ -993,7 +1049,9 @@ int idcvar_to_pyvar(
return CIP_FAILED;
// Call constructor
PYW_GIL_ENSURE;
obj = PyObject_CallFunctionObjArgs(py_cls, NULL);
PYW_GIL_RELEASE;
Py_DECREF(py_cls);
if ( PyW_GetError() || obj == NULL )
return CIP_FAILED;
@ -1045,11 +1103,104 @@ int idcvar_to_pyvar(
return CIP_OK;
}
//-------------------------------------------------------------------------
// Converts IDC arguments to Python argument list or just one tuple
// If 'decref' is NULL then 'pargs' will contain one element which is the tuple
bool pyw_convert_idc_args(
const idc_value_t args[],
int nargs,
ppyobject_vec_t &pargs,
boolvec_t *decref,
char *errbuf,
size_t errbufsize)
{
bool as_tupple = decref == NULL;
PyObject *py_tuple(NULL);
pargs.qclear();
if ( as_tupple )
{
py_tuple = PyTuple_New(nargs);
if ( py_tuple == NULL )
{
if ( errbuf != 0 && errbufsize > 0 )
qstrncpy(errbuf, "Failed to create a new tuple to store arguments!", errbufsize);
return false;
}
// Add the tuple
pargs.push_back(py_tuple);
}
else
{
decref->qclear();
}
for ( int i=0; i<nargs; i++ )
{
PyObject *py_obj(NULL);
int cvt = idcvar_to_pyvar(args[i], &py_obj);
if ( cvt < CIP_OK )
{
if ( errbuf != 0 && errbufsize > 0 )
qsnprintf(errbuf, errbufsize, "arg#%d has wrong type %d", i, args[i].vtype);
return false;
}
if ( as_tupple )
{
// Opaque object?
if ( cvt == CIP_OK_NODECREF )
{
// Increment reference for opaque objects.
// (A tupple will steal references of its set items,
// and for an opaque object we want it to still exist
// even if the tuple is gone)
Py_INCREF(py_obj);
}
// Save argument
PyTuple_SetItem(py_tuple, i, py_obj);
}
else
{
pargs.push_back(py_obj);
// Do not decrement reference of opaque objects
decref->push_back(cvt == CIP_OK);
}
}
return true;
}
//-------------------------------------------------------------------------
// Frees arguments returned by pyw_convert_idc_args()
void pyw_free_idc_args(
ppyobject_vec_t &pargs,
boolvec_t *decref)
{
if ( decref == NULL )
{
if ( !pargs.empty() )
Py_XDECREF(pargs[0]);
}
else
{
// free argument objects
for ( int i=(int)pargs.size()-1; i>=0; i-- )
{
if ( decref->at(i) )
Py_DECREF(pargs[i]);
}
decref->clear();
}
pargs.clear();
}
//------------------------------------------------------------------------
// String constants used
static const char S_PYINVOKE0[] = "_py_invoke0";
static const char S_PY_SWIEX_CLSNAME[] = "switch_info_ex_t";
static const char S_PY_OP_T_CLSNAME[] = "op_t";
static const char S_PROPS[] = "props";
@ -1121,6 +1272,22 @@ struct py_add_del_menu_item_ctx
PyObject *cb_data;
};
//---------------------------------------------------------------------------
// Context structure used by add|del_idc_hotkey()
struct py_idchotkey_ctx_t
{
qstring hotkey;
PyObject *pyfunc;
};
//---------------------------------------------------------------------------
// Context structure used by register/unregister timer
struct py_timer_ctx_t
{
qtimer_t timer_id;
PyObject *pycallback;
};
//------------------------------------------------------------------------
const char *pywraps_check_autoscripts()
{
@ -1146,6 +1313,43 @@ const char *pywraps_check_autoscripts()
return NULL;
}
//------------------------------------------------------------------------
error_t PyW_CreateIdcException(idc_value_t *res, const char *msg)
{
// Create exception object
VarObject(res, find_idc_class("exception"));
// Set the message field
idc_value_t v;
v.set_string(msg);
VarSetAttr(res, "message", &v);
// Throw exception
return set_qerrno(eExecThrow);
}
//------------------------------------------------------------------------
// Calls a Python callable encoded in IDC.pvoid member
static const char idc_py_invoke0_args[] = { VT_PVOID, 0 };
static error_t idaapi idc_py_invoke0(
idc_value_t *argv,
idc_value_t *res)
{
PyObject *pyfunc = (PyObject *) argv[0].pvoid;
PYW_GIL_ENSURE;
PyObject *py_result = PyObject_CallFunctionObjArgs(pyfunc, NULL);
PYW_GIL_RELEASE;
Py_XDECREF(py_result);
// Report Python error as IDC exception
qstring err;
if ( PyW_GetError(&err) )
return PyW_CreateIdcException(res, err.c_str());
return eOk;
}
//------------------------------------------------------------------------
// This function must be called on initialization
bool init_pywraps()
@ -1163,6 +1367,11 @@ bool init_pywraps()
return false;
}
// Register the IDC PyInvoke0 method (helper function for add_idc_hotkey())
if ( !set_idc_func_ex(S_PYINVOKE0, idc_py_invoke0, idc_py_invoke0_args, 0) )
return false;
// IDC opaque class not registered?
if ( get_py_idc_cvt_opaque() == NULL )
{
// Add the class
@ -1196,6 +1405,9 @@ void deinit_pywraps()
pywraps_initialized = false;
Py_XDECREF(py_cvt_helper_module);
py_cvt_helper_module = NULL;
// Unregister the IDC PyInvoke0 method (helper function for add_idc_hotkey())
set_idc_func_ex(S_PYINVOKE0, NULL, idc_py_invoke0_args, 0);
}
//------------------------------------------------------------------------
@ -1250,7 +1462,7 @@ PyObject *create_idaapi_linked_class_instance(
// This function takes a reference to the idaapi module and keeps the reference
PyObject *get_idaapi_attr_by_id(const int class_id)
{
if ( class_id >= PY_CLSID_LAST )
if ( class_id >= PY_CLSID_LAST || py_cvt_helper_module == NULL )
return NULL;
// Some class names. The array is parallel with the PY_CLSID_xxx consts
@ -1267,7 +1479,9 @@ PyObject *get_idaapi_attr_by_id(const int class_id)
// Gets a class reference by name
PyObject *get_idaapi_attr(const char *attrname)
{
return PyW_TryGetAttrString(py_cvt_helper_module, attrname);
return py_cvt_helper_module == NULL
? NULL
: PyW_TryGetAttrString(py_cvt_helper_module, attrname);
}
//------------------------------------------------------------------------
@ -1467,7 +1681,7 @@ bool PyW_ObjectToString(PyObject *obj, qstring *out)
//--------------------------------------------------------------------------
// Checks if a Python error occured and fills the out parameter with the
// exception string
bool PyW_GetError(qstring *out)
bool PyW_GetError(qstring *out, bool clear_err)
{
if ( PyErr_Occurred() == NULL )
return false;
@ -1476,14 +1690,77 @@ bool PyW_GetError(qstring *out)
if ( out == NULL )
{
// Just clear the error
if ( clear_err )
PyErr_Clear();
return true;
}
// Get the exception info
PyObject *err_type, *err_value, *err_traceback, *py_ret(NULL);
PyErr_Fetch(&err_type, &err_value, &err_traceback);
if ( !clear_err )
PyErr_Restore(err_type, err_value, err_traceback);
// Resolve FormatExc()
PyObject *py_fmtexc = get_idaapi_attr(S_IDAAPI_FORMATEXC);
// Helper there?
if ( py_fmtexc != NULL )
{
// Call helper
PYW_GIL_ENSURE;
py_ret = PyObject_CallFunctionObjArgs(
py_fmtexc,
err_type,
err_value,
err_traceback,
NULL);
PYW_GIL_RELEASE;
// Dispose helper reference
Py_DECREF(py_fmtexc);
}
// Clear the error
if ( clear_err )
PyErr_Clear();
// Helper failed?!
if ( py_ret == NULL )
{
// Just convert the 'value' part of the original error
py_ret = PyObject_Str(err_value);
}
// No exception text?
if ( py_ret == NULL )
{
*out = "IDAPython: unknown error!";
}
else
{
PyObject *err_type, *err_value, *err_traceback;
PyErr_Fetch(&err_type, &err_value, &err_traceback);
PyW_ObjectToString(err_value, out);
*out = PyString_AsString(py_ret);
Py_DECREF(py_ret);
}
if ( clear_err )
{
Py_XDECREF(err_traceback);
Py_XDECREF(err_value);
Py_XDECREF(err_type);
}
return true;
}
//-------------------------------------------------------------------------
bool PyW_GetError(char *buf, size_t bufsz, bool clear_err)
{
qstring s;
if ( !PyW_GetError(&s, clear_err) )
return false;
qstrncpy(buf, s.c_str(), bufsz);
return true;
}
@ -1770,11 +2047,11 @@ bool pywraps_nw_term()
{
if ( g_nw == NULL )
return true;
// If could not deinitialize then return w/o stopping nw
if ( !g_nw->deinit() )
return false;
// Cleanup
delete g_nw;
g_nw = NULL;
@ -1874,7 +2151,9 @@ class pyidc_opaque_object_t(object):
# -----------------------------------------------------------------------
class py_clinked_object_t(pyidc_opaque_object_t):
"""This is a utility and base class for C linked objects"""
"""
This is a utility and base class for C linked objects
"""
def __init__(self, lnk = None):
# static link: if a link was provided
self.__static_clink__ = True if lnk else False
@ -1884,22 +2163,13 @@ class py_clinked_object_t(pyidc_opaque_object_t):
def __del__(self):
"""Delete the link upon object destruction (only if not static)"""
if not self.__static_clink__:
self._free()
def _free(self):
"""Explicitly delete the link (only if not static)"""
if not self.__static_clink__ and self.__clink__ is not None:
self._del_clink(self.__clink__)
def _create_clink(self):
"""
Overwrite me.
Creates a new clink
@return: PyCObject representing the C link
"""
pass
def _del_clink(self, lnk):
"""Overwrite me.
This method deletes the link
"""
pass
self.__clink__ = None
def copy(self):
"""Returns a new copy of this class"""
@ -1912,6 +2182,31 @@ class py_clinked_object_t(pyidc_opaque_object_t):
return inst
#
# Methods to be overwritten
#
def _create_clink(self):
"""
Overwrite me.
Creates a new clink
@return: PyCObject representing the C link
"""
pass
def _del_clink(self, lnk):
"""
Overwrite me.
This method deletes the link
"""
pass
def _get_clink_ptr(self):
"""
Overwrite me.
Returns the C link pointer as a 64bit number
"""
pass
def assign(self, other):
"""
Overwrite me.
@ -1921,6 +2216,10 @@ class py_clinked_object_t(pyidc_opaque_object_t):
pass
clink = property(lambda self: self.__clink__)
"""Returns the C link as a PyObject"""
clink_ptr = property(lambda self: self._get_clink_ptr())
"""Returns the C link pointer as a number"""
# -----------------------------------------------------------------------
class object_t(object):
@ -1996,6 +2295,75 @@ class PyIdc_cvt_int64__(pyidc_cvt_helper__):
def __rmul__(self, other): return self.__op(2, other, True)
def __rdiv__(self, other): return self.__op(3, other, True)
# -----------------------------------------------------------------------
# qstrvec_t clinked object
class qstrvec_t(py_clinked_object_t):
"""Class representing an qstrvec_t"""
def __init__(self, items=None):
py_clinked_object_t.__init__(self)
# Populate the list if needed
if items:
self.from_list(items)
def _create_clink(self):
return _idaapi.qstrvec_t_create()
def _del_clink(self, lnk):
return _idaapi.qstrvec_t_destroy(lnk)
def _get_clink_ptr(self):
return _idaapi.qstrvec_t_get_clink_ptr(self)
def assign(self, other):
"""Copies the contents of 'other' to 'self'"""
return _idaapi.qstrvec_t_assign(self, other)
def __setitem__(self, idx, s):
"""Sets string at the given index"""
return _idaapi.qstrvec_t_set(self, idx, s)
def __getitem__(self, idx):
"""Gets the string at the given index"""
return _idaapi.qstrvec_t_get(self, idx)
def __get_size(self):
return _idaapi.qstrvec_t_size(self)
size = property(__get_size)
"""Returns the count of elements"""
def addressof(self, idx):
"""Returns the address (as number) of the qstring at the given index"""
return _idaapi.qstrvec_t_addressof(self, idx)
def add(self, s):
"""Add a string to the vector"""
return _idaapi.qstrvec_t_add(self, s)
def from_list(self, lst):
"""Populates the vector from a Python string list"""
return _idaapi.qstrvec_t_from_list(self, lst)
def clear(self, qclear=False):
"""
Clears all strings from the vector.
@param qclear: Just reset the size but do not actually free the memory
"""
return _idaapi.qstrvec_t_clear(self, qclear)
def insert(self, idx, s):
"""Insert a string into the vector"""
return _idaapi.qstrvec_t_insert(self, idx, s)
def remove(self, idx):
"""Removes a string from the vector"""
return _idaapi.qstrvec_t_remove(self, idx)
# -----------------------------------------------------------------------
class PyIdc_cvt_refclass__(pyidc_cvt_helper__):
"""Helper class for representing references to immutable objects"""
@ -2098,8 +2466,19 @@ def IDAPython_ExecSystem(cmd):
s = ''.join(f.readlines())
f.close()
return s
except Exception, e:
return str(e)
except Exception as e:
return "%s\n%s" % (str(e), traceback.format_exc())
# ------------------------------------------------------------
def IDAPython_FormatExc(etype, value, tb, limit=None):
"""
This function is used to format an exception given the
values returned by a PyErr_Fetch()
"""
try:
return ''.join(traceback.format_exception(etype, value, tb, limit))
except:
return str(value)
# ------------------------------------------------------------
@ -2125,12 +2504,12 @@ def IDAPython_ExecScript(script, g):
old__file__ = g['__file__'] if '__file__' in g else ''
g['__file__'] = script
PY_COMPILE_ERR = None
try:
execfile(script, g)
except Exception, e:
PY_COMPILE_ERR = str(e) + "\n" + traceback.format_exc()
print PY_COMPILE_ERR
PY_COMPILE_ERR = None
except Exception as e:
PY_COMPILE_ERR = "%s\n%s" % (str(e), traceback.format_exc())
print(PY_COMPILE_ERR)
finally:
# Restore the globals to the state before the script was run
g['__file__'] = old__file__
@ -2156,7 +2535,9 @@ class __IDAPython_Completion_Util(object):
@staticmethod
def parse_identifier(line, prefix, prefix_start):
"""Parse a line and extracts"""
"""
Parse a line and extracts identifier
"""
id_start = prefix_start
while id_start > 0:
ch = line[id_start]
@ -2181,7 +2562,7 @@ class __IDAPython_Completion_Util(object):
for i in xrange(0, c-1):
m = getattr(m, parts[i])
except Exception, e:
except Exception as e:
return (None, None)
else:
# search in the module
@ -2388,6 +2769,112 @@ def RunPythonStatement(stmt):
#</pydoc>
*/
//---------------------------------------------------------------------------
// qstrvec_t wrapper
//---------------------------------------------------------------------------
DECLARE_PY_CLINKED_OBJECT(qstrvec_t);
static bool qstrvec_t_assign(PyObject *self, PyObject *other)
{
qstrvec_t *lhs = qstrvec_t_get_clink(self);
qstrvec_t *rhs = qstrvec_t_get_clink(other);
if (lhs == NULL || rhs == NULL)
return false;
*lhs = *rhs;
return true;
}
static PyObject *qstrvec_t_addressof(PyObject *self, size_t idx)
{
qstrvec_t *sv = qstrvec_t_get_clink(self);
if ( sv == NULL || idx >= sv->size() )
Py_RETURN_NONE;
else
return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)&sv->at(idx));
}
static bool qstrvec_t_set(
PyObject *self,
size_t idx,
const char *s)
{
qstrvec_t *sv = qstrvec_t_get_clink(self);
if ( sv == NULL || idx >= sv->size() )
return false;
(*sv)[idx] = s;
return true;
}
static bool qstrvec_t_from_list(
PyObject *self,
PyObject *py_list)
{
qstrvec_t *sv = qstrvec_t_get_clink(self);
return sv == NULL ? false : PyW_PyListToStrVec(py_list, *sv);
}
static size_t qstrvec_t_size(PyObject *self)
{
qstrvec_t *sv = qstrvec_t_get_clink(self);
return sv == NULL ? 0 : sv->size();
}
static PyObject *qstrvec_t_get(PyObject *self, size_t idx)
{
qstrvec_t *sv = qstrvec_t_get_clink(self);
if ( sv == NULL || idx >= sv->size() )
Py_RETURN_NONE;
return PyString_FromString(sv->at(idx).c_str());
}
static bool qstrvec_t_add(PyObject *self, const char *s)
{
qstrvec_t *sv = qstrvec_t_get_clink(self);
if ( sv == NULL )
return false;
sv->push_back(s);
return true;
}
static bool qstrvec_t_clear(PyObject *self, bool qclear)
{
qstrvec_t *sv = qstrvec_t_get_clink(self);
if ( sv == NULL )
return false;
if ( qclear )
sv->qclear();
else
sv->clear();
return true;
}
static bool qstrvec_t_insert(
PyObject *self,
size_t idx,
const char *s)
{
qstrvec_t *sv = qstrvec_t_get_clink(self);
if ( sv == NULL || idx >= sv->size() )
return false;
sv->insert(sv->begin() + idx, s);
return true;
}
static bool qstrvec_t_remove(PyObject *self, size_t idx)
{
qstrvec_t *sv = qstrvec_t_get_clink(self);
if ( sv == NULL || idx >= sv->size() )
return false;
sv->erase(sv->begin()+idx);
return true;
}
//---------------------------------------------------------------------------
//------------------------------------------------------------------------

View File

@ -90,7 +90,7 @@ PyObject *py_appcall(
if ( !ok )
{
PyErr_SetString(
PyExc_ValueError,
PyExc_ValueError,
"PyAppCall: Failed to convert Python values to IDC values");
return NULL;
}
@ -275,9 +275,9 @@ static PyObject *dbg_get_thread_sreg_base(PyObject *py_tid, PyObject *py_sreg_va
ea_t answer;
thid_t tid = PyInt_AsLong(py_tid);
int sreg_value = PyInt_AsLong(py_sreg_value);
if ( dbg->thread_get_sreg_base(tid, sreg_value, &answer) != 1 )
if ( internal_get_sreg_base(tid, sreg_value, &answer) != 1 )
Py_RETURN_NONE;
return Py_BuildValue(PY_FMT64, pyul_t(answer));
}
@ -310,7 +310,7 @@ static PyObject *dbg_read_memory(PyObject *py_ea, PyObject *py_sz)
char *buf;
PyString_AsStringAndSize(ret, &buf, &len);
if ( (size_t)dbg->read_memory(ea_t(ea), buf, size_t(sz)) != sz )
if ( (size_t)read_dbg_memory(ea_t(ea), buf, size_t(sz)) != sz )
{
// Release the string on failure
Py_DECREF(ret);
@ -339,7 +339,7 @@ static PyObject *dbg_write_memory(PyObject *py_ea, PyObject *py_buf)
size_t sz = PyString_GET_SIZE(py_buf);
void *buf = (void *)PyString_AS_STRING(py_buf);
if ( dbg->write_memory(ea_t(ea), buf, sz) != sz )
if ( write_dbg_memory(ea_t(ea), buf, sz) != sz )
Py_RETURN_FALSE;
Py_RETURN_TRUE;
}
@ -386,7 +386,7 @@ static PyObject *dbg_get_memory_info()
invalidate_dbgmem_contents(BADADDR, BADADDR);
meminfo_vec_t areas;
dbg->get_memory_info(areas);
get_dbg_memory_info(&areas);
return meminfo_vec_t_to_py(areas);
}
@ -587,7 +587,7 @@ class Appcall_callable__(object):
self.type,
self.fields,
arg_list)
except Exception, e:
except Exception as e:
e_obj = e
# Restore appcall options

View File

@ -423,7 +423,7 @@ static PyObject *ph_get_operand_info(
regvals_t regvalues;
regvalues.resize(dbg->registers_size);
// Read registers
if ( dbg->read_registers(tid, -1, regvalues.begin()) != 1 )
if ( get_reg_vals(tid, -1, regvalues.begin()) != 1 )
break;
// Call the processor module
@ -749,7 +749,7 @@ public:
virtual PyObject *custom_mnem()
{
return NULL;
Py_RETURN_NONE;
}
virtual int is_sane_insn(int no_crefs)
@ -825,7 +825,7 @@ public:
bool /*use32*/,
const char * /*line*/)
{
return NULL;
Py_RETURN_NONE;
}
};
@ -865,7 +865,7 @@ public:
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_deleted(struc_t * /*sptr*/, tid_t /*member_id*/, ea_t /*offset*/) { 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; };
@ -1067,6 +1067,303 @@ int idaapi IDP_Callback(void *ud, int notification_code, va_list va)
Py_XDECREF(py_buffer);
break;
}
// validate_flirt_func, // flirt has recognized a library function
// // this callback can be used by a plugin or proc module
// // to intercept it and validate such a function
// // args: ea_t start_ea
// // const char *funcname
// // returns: -1-do not create a function,
// // 1-function is validated
// // the idp module is allowed to modify 'cmd'
// set_func_start, // Function chunk start address will be changed
// // args: func_t *pfn
// // ea_t new_start
// // Returns: 1-ok,<=0-do not change
// set_func_end, // Function chunk end address will be changed
// // args: func_t *pfn
// // ea_t new_end
// // Returns: 1-ok,<=0-do not change
// outlabel, // The kernel is going to generate an instruction
// // label line or a function header
// // args:
// // ea_t ea -
// // const char *colored_name -
// // If returns value <=0, then the kernel should
// // not generate the label
// may_show_sreg, // The kernel wants to display the segment registers
// // in the messages window.
// // arg - ea_t current_ea
// // if this function returns 0
// // then the kernel will not show
// // the segment registers.
// // (assuming that the module have done it)
// coagulate, // Try to define some unexplored bytes
// // This notification will be called if the
// // kernel tried all possibilities and could
// // not find anything more useful than to
// // convert to array of bytes.
// // The module can help the kernel and convert
// // the bytes into something more useful.
// // arg:
// // ea_t start_ea
// // returns: number of converted bytes + 1
// auto_empty, // Info: all analysis queues are empty
// // args: none
// // returns: none
// // This callback is called once when the
// // initial analysis is finished. If the queue is
// // not empty upon the return from this callback,
// // it will be called later again.
// // See also auto_empty_finally.
// auto_queue_empty, // One analysis queue is empty
// // args: atype_t type
// // returns: 1-yes, keep the queue empty
// // <=0-no, the queue is not empty anymore
// // This callback can be called many times, so
// // only the autoMark() functions can be used from it
// // (other functions may work but it is not tested)
// func_bounds, // find_func_bounds() finished its work
// // The module may fine tune the function bounds
// // args: int *possible_return_code
// // func_t *pfn
// // ea_t max_func_end_ea (from the kernel's point of view)
// // returns: none
// is_jump_func, // is the function a trivial "jump" function?
// // args: func_t *pfn
// // ea_t *jump_target
// // ea_t *func_pointer
// // returns: 0-no, 1-don't know, 2-yes, see jump_target
// // and func_pointer
// gen_regvar_def, // generate register variable definition line
// // args: regvar_t *v
// // returns: 0-ok
// setsgr, // The kernel has changed a segment register value
// // args: ea_t startEA
// // ea_t endEA
// // int regnum
// // sel_t value
// // sel_t old_value
// // uchar tag (SR_... values)
// // returns: 1-ok, 0-error
// set_compiler, // The kernel has changed the compiler information
// // (inf.cc structure)
// is_basic_block_end, // Is the current instruction end of a basic block?
// // This function should be defined for processors
// // with delayed jump slots. The current instruction
// // is stored in 'cmd'
// // args: bool call_insn_stops_block
// // returns: 1-unknown, 0-no, 2-yes
// reglink, // IBM PC only, ignore it
// get_vxd_name, // IBM PC only, ignore it
// // Get Vxd function name
// // args: int vxdnum
// // int funcnum
// // char *outbuf
// // returns: nothing
//
//
// moving_segm, // May the kernel move the segment?
// // args: segment_t - segment to move
// // ea_t to - new segment start address
// // returns: 1-yes, <=0-the kernel should stop
// move_segm, // A segment is moved
// // Fix processor dependent address sensitive information
// // args: ea_t from - old segment address
// // segment_t* - moved segment
// // returns: nothing
//
//
// get_stkvar_scale_factor,// Should stack variable references be multiplied by
// // a coefficient before being used in the stack frame?
// // Currently used by TMS320C55 because the references into
// // the stack should be multiplied by 2
// // Returns: scaling factor
// // Note: PR_SCALE_STKVARS should be set to use this callback
//
// create_flat_group, // Create special segment representing the flat group
// // (to use for PC mainly)
// // args - ea_t image_base, int bitness, sel_t dataseg_sel
//
// kernel_config_loaded, // This callback is called when ida.cfg is parsed
// // args - none, returns - nothing
//
// might_change_sp, // Does the instruction at 'ea' modify the stack pointer?
// // args: ea_t ea
// // returns: 1-yes, 0-false
// // (not used yet)
//
// is_alloca_probe, // Does the function at 'ea' behave as __alloca_probe?
// // args: ea_t ea
// // returns: 2-yes, 1-false
//
// out_3byte, // Generate text representation of 3byte data
// // init_out_buffer() is called before this function
// // and all Out... function can be used.
// // uFlag contains the flags.
// // This callback might be implemented by the processor
// // module to generate custom representation of 3byte data.
// // args:
// // ea_t dataea - address of the data item
// // uint32 value - value to output
// // bool analyze_only - only create xrefs if necessary
// // do not generate text representation
// // returns: 2-yes, 1-false
//
// get_reg_name, // Generate text representation of a register
// // int reg - internal register number as defined in the processor module
// // size_t width - register width in bytes
// // char *buf - output buffer
// // size_t bufsize - size of output buffer
// // int reghi - if not -1 then this function will return the register pair
// // returns: -1 if error, strlen(buf)+2 otherwise
// // Most processor modules do not need to implement this callback
// // It is useful only if ph.regNames[reg] does not provide
// // the correct register names
// // save its local data
// out_src_file_lnnum, // Callback: generate analog of
// // #line "file.c" 123
// // directive.
// // const char *file - source file (may be NULL)
// // size_t lnnum - line number
// // returns: 2-directive has been generated
// get_autocmt, // Callback: get dynamic auto comment
// // Will be called if the autocomments are enabled
// // and the comment retrieved from ida.int starts with
// // '$!'. 'cmd' is contains valid info.
// // char *buf - output buffer
// // size_t bufsize - output buffer size
// // returns: 2-new comment has been generated
// // 1-callback has not been handled
// // the buffer must not be changed in this case
// is_insn_table_jump, // Callback: determine if instruction is a table jump or call
// // If CF_JUMP bit can not describe all kinds of table
// // jumps, please define this callback.
// // It will be called for insns with CF_JUMP bit set.
// // input: cmd structure contains the current instruction
// // returns: 1-yes, 0-no
// auto_empty_finally, // Info: all analysis queues are empty definitively
// // args: none
// // returns: none
// // This callback is called only once.
// // See also auto_empty.
// loader_finished, // Event: external file loader finished its work
// // linput_t *li
// // uint16 neflags
// // const char *filetypename
// // Use this event to augment the existing loader functionality
// loader_elf_machine, // Event: ELF loader machine type checkpoint
// // linput_t *li
// // int machine_type
// // const char **p_procname
// // proc_def **p_pd (see ldr\elf.h)
// // set_elf_reloc_t *set_reloc
// // A plugin check the machine_type. If it is the desired one,
// // the the plugin fills p_procname with the processor name.
// // p_pd is used to handle relocations, otherwise can be left untouched
// // set_reloc can be later used by the plugin to specify relocations
// // returns: e_machine value (if it is different from the
// // original e_machine value, procname and p_pd will be ignored
// // and the new value will be used)
// // This event occurs for each loaded ELF file
// is_indirect_jump, // Callback: determine if instruction is an indrect jump
// // If CF_JUMP bit can not describe all jump types
// // jumps, please define this callback.
// // input: cmd structure contains the current instruction
// // returns: 1-use CF_JUMP, 2-no, 3-yes
// verify_noreturn, // The kernel wants to set 'noreturn' flags for a function
// // func_t *pfn
// // Returns: 1-ok, any other value-do not set 'noreturn' flag
// verify_sp, // All function instructions have been analyzed
// // Now the processor module can analyze the stack pointer
// // for the whole function
// // input: func_t *pfn
// // Returns: 1-ok, 0-bad stack pointer
// treat_hindering_item, // An item hinders creation of another item
// // args: ea_t hindering_item_ea
// // flags_t new_item_flags (0 for code)
// // ea_t new_item_ea
// // asize_t new_item_length
// // Returns: 1-no reaction, <=0-the kernel may delete the hindering item
// str2reg, // Convert a register name to a register number
// // args: const char *regname
// // Returns: register number + 2
// // The register number is the register index in the regNames array
// // Most processor modules do not need to implement this callback
// // It is useful only if ph.regNames[reg] does not provide
// // the correct register names
// create_switch_xrefs, // Create xrefs for a custom jump table
// // in: ea_t jumpea; - address of the jump insn
// // switch_info_ex_t *; - switch information
// // returns: must return 2
// calc_switch_cases, // Calculate case values and targets for a custom jump table
// // in: ea_t insn_ea - address of the 'indirect jump' instruction
// // switch_info_ex_t *si - switch information
// // casevec_t *casevec - vector of case values...
// // evec_t *targets - ...and corresponding target addresses
// // casevec and targets may be NULL
// // returns: 2-ok, 1-failed
// determined_main, // The main() function has been determined
// // in: ea_t main - address of the main() function
// // returns: none
// preprocess_chart, // gui has retrieved a function flow chart
// // in: qflow_chart_t *fc
// // returns: none
// // Plugins may modify the flow chart in this callback
// get_bg_color, // Get item background color
// // in: ea_t ea, bgcolor_t *color
// // Returns: 1-not implemented, 2-color set
// // Plugins can hook this callback to color disassembly lines
// // dynamically
// get_operand_string, // Request text string for operand (cli, java, ...)
// // args: int opnum
// // char *buf
// // size_t buflen
// // (cmd structure must contain info for the desired insn)
// // opnum is the operand number; -1 means any string operand
// // returns: 1 - no string (or empty string)
// // >1 - original string length with terminating zero
//
// // the following 5 events are very low level
// // take care of possible recursion
// add_cref, // a code reference is being created
// // args: ea_t from, ea_t to, cref_t type
// // returns: <0 - cancel cref creation
// add_dref, // a data reference is being created
// // args: ea_t from, ea_t to, dref_t type
// // returns: <0 - cancel dref creation
// del_cref, // a code reference is being deleted
// // args: ea_t from, ea_t to, bool expand
// // returns: <0 - cancel cref deletion
// del_dref, // a data reference is being deleted
// // args: ea_t from, ea_t to
// // returns: <0 - cancel dref deletion
// coagulate_dref, // data reference is being analyzed
// // args: ea_t from, ea_t to, bool may_define, ea_t *code_ea
// // plugin may correct code_ea (e.g. for thumb mode refs, we clear the last bit)
// // returns: <0 - cancel dref analysis
// custom_fixup, // mutipurpose notification for FIXUP_CUSTOM
// // args: cust_fix oper, ea_t ea, const fixup_data_t*, ... (see cust_fix)
// // returns: 1 - no accepted (fixup ignored by ida)
// // >1 - accepted (see cust_fix)
// off_preproc, // called from get_offset_expr, when refinfo_t
// // contain flag REFINFO_PREPROC. Normally this
// // notification used in a combination with custom_fixup
// // args: ea_t ea, int numop, ea_t* opval, const refinfo_t* ri,
// // char* buf, size_t bufsize, ea_t* target,
// // ea_t* fullvalue, ea_t from, int getn_flags
// // returns: 2 - buf filled as simple expression
// // 3 - buf filled as complex expression
// // 4 - apply standard processing (with - possible - changed values)
// // others - can't convert to offset expression
//
// set_proc_options, // called if the user specified an option string in the command line:
// // -p<processor name>:<options>
// // can be used for e.g. setting a processor subtype
// // also called if option string is passed to set_processor_type()
// // and IDC's SetProcessorType()
// // args: const char * options
// // returns: <0 - bad option string
//
}
}
catch (Swig::DirectorException &e)
@ -1190,7 +1487,8 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
case idb_event::struc_member_deleted:
sptr = va_arg(va, struc_t *);
member_id = va_arg(va, tid_t);
return proxy->struc_member_deleted(sptr, member_id);
ea = va_arg(va, ea_t);
return proxy->struc_member_deleted(sptr, member_id, ea);
case idb_event::struc_member_renamed:
sptr = va_arg(va, struc_t *);

File diff suppressed because it is too large Load Diff

View File

@ -115,6 +115,12 @@
%ignore mem2base;
%rename (mem2base) py_mem2base;
%ignore update_snapshot_attributes;
%ignore build_snapshot_tree;
%ignore visit_snapshot_tree;
%ignore save_database_ex;
%ignore snapshot_t;
%ignore snapshots_t;
%ignore load_plugin;
%rename (load_plugin) py_load_plugin;
%ignore run_plugin;
@ -170,8 +176,8 @@ static PyObject *py_load_plugin(const char *name)
plugin_t *r = load_plugin(name);
if ( r == NULL )
Py_RETURN_NONE;
return PyCObject_FromVoidPtr(r, NULL);
else
return PyCObject_FromVoidPtr(r, NULL);
}
//------------------------------------------------------------------------
@ -190,8 +196,8 @@ static bool py_run_plugin(PyObject *plg, int arg)
{
if ( !PyCObject_Check(plg) )
return false;
return run_plugin((plugin_t *)PyCObject_AsVoidPtr(plg), arg);
else
return run_plugin((plugin_t *)PyCObject_AsVoidPtr(plg), arg);
}
//</inline(py_loader)>

View File

@ -566,10 +566,10 @@ class switch_info_ex_t(py_clinked_object_t):
return (self.flags & SWI_EXTENDED) != 0 and (self.flags2 & SWI2_SUBTRACT) != 0
def get_jtable_size(self):
return self.jcases if self.is_indirect() else ncases
return self.jcases if self.is_indirect() else self.ncases
def get_lowcase(self):
return self.ind_lowcase if is_indirect() else self.lowcase
return self.ind_lowcase if self.is_indirect() else self.lowcase
def set_expr(self, r, dt):
self.regnum = r

View File

@ -90,7 +90,7 @@
%include "netnode.hpp"
%extend netnode
%extend netnode
{
nodeidx_t index()
{
@ -111,5 +111,26 @@
return py_str;
}
PyObject *hashstr_buf(const char *idx, char tag=htag)
{
char buf[MAXSPECSIZE];
ssize_t sz = self->hashstr(idx, buf, sizeof(buf), tag);
if ( sz < 0 )
Py_RETURN_NONE;
else
return PyString_FromStringAndSize(buf, sz);
}
bool hashset_buf(const char *idx, PyObject *py_str, char tag=htag)
{
char *buf;
Py_ssize_t sz;
if ( PyString_AsStringAndSize(py_str, &buf, &sz) == -1 )
return false;
else
return self->hashset(idx, buf, sz, tag);
}
}

View File

@ -6,7 +6,7 @@
%ignore print_all_counters;
%ignore incrementer_t;
%ignore reloc_info_t; // swig under mac chokes on this
%ignore qstrvec_t;
%ignore qmutex_create;
%ignore qiterator;
%ignore qrefcnt_t;
@ -86,3 +86,4 @@
%rename (parse_command_line) py_parse_command_line;
%include "pro.h"
SWIG_DECLARE_PY_CLINKED_OBJECT(qstrvec_t)

View File

@ -331,6 +331,31 @@ bool py_out_name_expr(
return op == NULL ? false : out_name_expr(*op, ea, off);
}
//-------------------------------------------------------------------------
static PyObject *insn_t_get_op_link(PyObject *py_insn_lnk, int i)
{
if ( i < 0 || i >= UA_MAXOP || !PyCObject_Check(py_insn_lnk) )
Py_RETURN_NONE;
// Extract C link
insn_t *insn = (insn_t *)PyCObject_AsVoidPtr(py_insn_lnk);
// Return a link to the operand
return PyCObject_FromVoidPtr(&insn->Operands[i], NULL);
}
//-------------------------------------------------------------------------
static PyObject *insn_t_create()
{
return PyCObject_FromVoidPtr(new insn_t(), NULL);
}
//-------------------------------------------------------------------------
static PyObject *op_t_create()
{
return PyCObject_FromVoidPtr(new op_t(), NULL);
}
//-------------------------------------------------------------------------
static bool op_t_assign(PyObject *self, PyObject *other)
{
@ -355,40 +380,13 @@ static bool insn_t_assign(PyObject *self, PyObject *other)
return true;
}
//-------------------------------------------------------------------------
static PyObject *insn_t_get_op_link(PyObject *py_insn_lnk, int i)
{
if ( i < 0 || i >= UA_MAXOP || !PyCObject_Check(py_insn_lnk) )
Py_RETURN_NONE;
// Extract C link
insn_t *insn = (insn_t *)PyCObject_AsVoidPtr(py_insn_lnk);
// Return a link to the operand
return PyCObject_FromVoidPtr(&insn->Operands[i], NULL);
}
//-------------------------------------------------------------------------
static PyObject *insn_t_create()
{
insn_t *insn = new insn_t();
return PyCObject_FromVoidPtr(insn, NULL);
}
//-------------------------------------------------------------------------
static PyObject *op_t_create()
{
op_t *op = new op_t();
return PyCObject_FromVoidPtr(op, NULL);
}
//-------------------------------------------------------------------------
static bool op_t_destroy(PyObject *py_obj)
{
if ( !PyCObject_Check(py_obj) )
return false;
op_t *op = (op_t *) PyCObject_AsVoidPtr(py_obj);
op_t *op = (op_t *)PyCObject_AsVoidPtr(py_obj);
delete op;
return true;
@ -400,9 +398,7 @@ static bool insn_t_destroy(PyObject *py_obj)
if ( !PyCObject_Check(py_obj) )
return false;
insn_t *insn = (insn_t *) PyCObject_AsVoidPtr(py_obj);
delete insn;
delete (insn_t *)PyCObject_AsVoidPtr(py_obj);
return true;
}
@ -856,12 +852,6 @@ class op_t(py_clinked_object_t):
"""Copies the contents of 'other' to 'self'"""
return _idaapi.op_t_assign(self, other)
#<pydoc>
# def copy(self):
# """Returns a new copy of this class"""
# pass
#</pydoc>
def __eq__(self, other):
"""Checks if two register operands are equal by checking the register number and its dtype"""
return (self.reg == other.reg) and (self.dtyp == other.dtyp)