mirror of
https://github.com/cemu-project/idapython.git
synced 2024-11-24 10:09:20 +01:00
- IDA Pro 6.1 support
- Added AskUsingForm() with embedded forms support (check ex_askusingform.py example and formchooser.py in the SDK) - Added idautils.DecodePreviousInstruction() / DecodePrecedingInstruction() - Added idc.BeginTypeUpdating() / EndTypeUpdating() for fast batch type update operations - Added more IDP callbacks - Added UI_Hooks with a few notification events - Added idaapi.process_ui_action() / idc.ProcessUiAction() - Added netnode.index() to get netnode number - Better handling of ea_t values with bitwise negation - Execute statement hotkey (Ctrl-F3), script timeout, and other options are now configurable with Python.cfg - bugfix: idaapi.msg() / error() and warning() so they don't accept vararg - bugfix: processor_t.id constants were incorrect - bugfix: get_debug_names() was broken with IDA64 - Various bugfixes
This commit is contained in:
parent
63b22d00d5
commit
109158fabb
29
CHANGES.txt
29
CHANGES.txt
@ -1,20 +1,40 @@
|
|||||||
Please see http://code.google.com/p/idapython/source/list for a detailed list of changes.
|
Please see http://code.google.com/p/idapython/source/list for a detailed list of changes.
|
||||||
|
|
||||||
|
|
||||||
|
Changes from version 1.4.3 to 1.5.0
|
||||||
|
------------------------------------
|
||||||
|
- IDA Pro 6.1 support
|
||||||
|
- Added AskUsingForm() with embedded forms support (check ex_askusingform.py example and formchooser.py in the SDK)
|
||||||
|
- Added idautils.DecodePreviousInstruction() / DecodePrecedingInstruction()
|
||||||
|
- Added idc.BeginTypeUpdating() / EndTypeUpdating() for fast batch type update operations
|
||||||
|
- Added more IDP callbacks
|
||||||
|
- Added UI_Hooks with a few notification events
|
||||||
|
- Added idaapi.process_ui_action() / idc.ProcessUiAction()
|
||||||
|
- Added netnode.index() to get netnode number
|
||||||
|
- Better handling of ea_t values with bitwise negation
|
||||||
|
- Execute statement hotkey (Ctrl-F3), script timeout, and other options are now configurable with Python.cfg
|
||||||
|
- bugfix: idaapi.msg() / error() and warning() so they don't accept vararg
|
||||||
|
- bugfix: processor_t.id constants were incorrect
|
||||||
|
- bugfix: get_debug_names() was broken with IDA64
|
||||||
|
- Various bugfixes
|
||||||
|
|
||||||
Changes from version 1.4.2 to 1.4.3
|
Changes from version 1.4.2 to 1.4.3
|
||||||
------------------------------------
|
------------------------------------
|
||||||
- IDA 6.0 support
|
- IDA Pro 6.0 support
|
||||||
- Python CLI now prints expression evaluation result (no need to use print())
|
- Python CLI now prints expression evaluation result (no need to use print())
|
||||||
- Changed Alt-8 to Ctrl-F3 (because it conflicts with window switching key Alt+n)
|
- Changed Alt-8 to Ctrl-F3 (because it conflicts with window switching key Alt+n)
|
||||||
- Added get_highlighted_identifier()
|
- Added get_highlighted_identifier()
|
||||||
- Added PluginForm class to allow UI development with either PyQt4 or PySide
|
- Added PluginForm class to allow UI development with either PyQt4 or PySide
|
||||||
- Added idautils.Entries() to enum entrypoints
|
- Added idautils.Entries() to enum entrypoints
|
||||||
|
|
||||||
|
|
||||||
Changes from version 1.4.1 to 1.4.2
|
Changes from version 1.4.1 to 1.4.2
|
||||||
------------------------------------
|
------------------------------------
|
||||||
- Added command completion
|
- Added command completion
|
||||||
- Added necessary changes so it compiles with Python 2.7
|
- Added necessary changes so it compiles with Python 2.7
|
||||||
- Wrapped set_user_defined_prefix()
|
- Wrapped set_user_defined_prefix()
|
||||||
|
|
||||||
|
|
||||||
Changes from version 1.4.0 to 1.4.1
|
Changes from version 1.4.0 to 1.4.1
|
||||||
------------------------------------
|
------------------------------------
|
||||||
- Added cli_t
|
- Added cli_t
|
||||||
@ -22,6 +42,7 @@ Changes from version 1.4.0 to 1.4.1
|
|||||||
- Changed the copyright string to IDAPython Team
|
- Changed the copyright string to IDAPython Team
|
||||||
- Some platform dependant classes are present but useable only where applicable
|
- Some platform dependant classes are present but useable only where applicable
|
||||||
|
|
||||||
|
|
||||||
Changes from version 1.3.0 to 1.4.0
|
Changes from version 1.3.0 to 1.4.0
|
||||||
------------------------------------
|
------------------------------------
|
||||||
- IDA Pro 5.7 support
|
- IDA Pro 5.7 support
|
||||||
@ -35,9 +56,9 @@ Changes from version 1.3.0 to 1.4.0
|
|||||||
- Documented all manually wrapped functions (check 'pywraps' module in the docs)
|
- Documented all manually wrapped functions (check 'pywraps' module in the docs)
|
||||||
- Lots of cleanups and fixes
|
- Lots of cleanups and fixes
|
||||||
|
|
||||||
|
|
||||||
Changes from version 1.2.0 to 1.3.0
|
Changes from version 1.2.0 to 1.3.0
|
||||||
------------------------------------
|
------------------------------------
|
||||||
|
|
||||||
- IDA Pro 5.6 support
|
- IDA Pro 5.6 support
|
||||||
- Added Appcall mechanism
|
- Added Appcall mechanism
|
||||||
- Added procregs to idautils.py (r254)
|
- Added procregs to idautils.py (r254)
|
||||||
@ -45,7 +66,6 @@ Changes from version 1.2.0 to 1.3.0
|
|||||||
|
|
||||||
Changes from version 1.1.0 to 1.2.0
|
Changes from version 1.1.0 to 1.2.0
|
||||||
------------------------------------
|
------------------------------------
|
||||||
|
|
||||||
- 64-bit support (largely untested)
|
- 64-bit support (largely untested)
|
||||||
- IDA Pro 5.5 support
|
- IDA Pro 5.5 support
|
||||||
- Long running (or inifinitely looping) scripts can now be stopped
|
- Long running (or inifinitely looping) scripts can now be stopped
|
||||||
@ -58,7 +78,6 @@ Changes from version 1.1.0 to 1.2.0
|
|||||||
|
|
||||||
Changes from version 0.9.0 to 1.0.0
|
Changes from version 0.9.0 to 1.0.0
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
- Upgraded IDA Pro base version to 5.1
|
- Upgraded IDA Pro base version to 5.1
|
||||||
- Dropped Python 2.4 support
|
- Dropped Python 2.4 support
|
||||||
- Mac OS X support
|
- Mac OS X support
|
||||||
@ -76,7 +95,6 @@ Changes from version 0.9.0 to 1.0.0
|
|||||||
|
|
||||||
Changes from version 0.8.0 to 0.9.0
|
Changes from version 0.8.0 to 0.9.0
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
- Upgraded base version to IDA Pro 5.0
|
- Upgraded base version to IDA Pro 5.0
|
||||||
- Works with IDA Pro 5.1
|
- Works with IDA Pro 5.1
|
||||||
- Python 2.4 and 2.5 supported
|
- Python 2.4 and 2.5 supported
|
||||||
@ -92,7 +110,6 @@ Changes from version 0.8.0 to 0.9.0
|
|||||||
|
|
||||||
Changes from version 0.7.0 to 0.8.0
|
Changes from version 0.7.0 to 0.8.0
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
- Added support for IDA Pro 4.9
|
- Added support for IDA Pro 4.9
|
||||||
- Dropped support for IDA Pro 4.7
|
- Dropped support for IDA Pro 4.7
|
||||||
- NOTE: Windows version is linked against Python 2.4.
|
- NOTE: Windows version is linked against Python 2.4.
|
||||||
|
@ -38,10 +38,10 @@ Mailing list for the project is hosted by Google Groups at
|
|||||||
INSTALLATION FROM BINARIES
|
INSTALLATION FROM BINARIES
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
1. Install Python 2.5 or 2.6 from http://www.python.org/
|
1. Install 2.6 or 2.7 from http://www.python.org/
|
||||||
2. Copy the python and python64 directories to the IDA install directory
|
2. Copy "python" directory to %IDADIR%
|
||||||
3. Copy the plugins to the %IDADIR%\plugins\
|
3. Copy "plugins" directory to the %IDADIR%\plugins\
|
||||||
|
4. Copy "python.cfg" to %IDADIR%\cfg
|
||||||
|
|
||||||
USAGE
|
USAGE
|
||||||
-----
|
-----
|
||||||
@ -88,3 +88,4 @@ or
|
|||||||
|
|
||||||
The user init file is read and executed at the end of the init process.
|
The user init file is read and executed at the end of the init process.
|
||||||
|
|
||||||
|
Please note that IDAPython can be configured with "python.cfg" file.
|
||||||
|
216
Scripts/AsmViewer.py
Normal file
216
Scripts/AsmViewer.py
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# This is an example illustrating how to use customview in Python
|
||||||
|
# The sample will allow you to open an assembly file and display it in color
|
||||||
|
# (c) Hex-Rays
|
||||||
|
#
|
||||||
|
import idaapi
|
||||||
|
import idautils
|
||||||
|
import idc
|
||||||
|
import os
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
class asm_colorizer_t(object):
|
||||||
|
def is_id(self, ch):
|
||||||
|
return ch == '_' or ch.isalpha() or '0' <= ch <= '9'
|
||||||
|
|
||||||
|
def get_identifier(self, line, x, e):
|
||||||
|
i = x
|
||||||
|
is_digit = line[i].isdigit()
|
||||||
|
while i < e:
|
||||||
|
ch = line[i]
|
||||||
|
if not self.is_id(ch):
|
||||||
|
if ch != '.' or not is_digit:
|
||||||
|
break
|
||||||
|
i += 1
|
||||||
|
return (i, line[x:i])
|
||||||
|
|
||||||
|
def get_quoted_string(self, line, x, e):
|
||||||
|
quote = line[x]
|
||||||
|
i = x + 1
|
||||||
|
while i < e:
|
||||||
|
ch = line[i]
|
||||||
|
if ch == '\\' and line[i+1] == quote:
|
||||||
|
i += 1
|
||||||
|
elif ch == quote:
|
||||||
|
i += 1 # also take the quote
|
||||||
|
break
|
||||||
|
i += 1
|
||||||
|
return (i, line[x:i])
|
||||||
|
|
||||||
|
def colorize(self, lines):
|
||||||
|
for line in lines:
|
||||||
|
line = line.rstrip()
|
||||||
|
if not line:
|
||||||
|
self.add_line()
|
||||||
|
continue
|
||||||
|
x = 0
|
||||||
|
e = len(line)
|
||||||
|
s = ""
|
||||||
|
while x < e:
|
||||||
|
ch = line[x]
|
||||||
|
# String?
|
||||||
|
if ch == '"' or ch == "'":
|
||||||
|
x, w = self.get_quoted_string(line, x, e)
|
||||||
|
s += self.as_string(w)
|
||||||
|
# Tab?
|
||||||
|
elif ch == '\t':
|
||||||
|
s += ' ' * 4
|
||||||
|
x += 1
|
||||||
|
# Comment?
|
||||||
|
elif ch == ';':
|
||||||
|
s += self.as_comment(line[x:])
|
||||||
|
# Done with this line
|
||||||
|
break
|
||||||
|
elif ch == '.' and x + 1 < e:
|
||||||
|
x, w = self.get_identifier(line, x + 1, e)
|
||||||
|
s += self.as_directive(ch + w)
|
||||||
|
# Identifiers?
|
||||||
|
elif self.is_id(ch):
|
||||||
|
x, w = self.get_identifier(line, x, e)
|
||||||
|
# Number?
|
||||||
|
if ch.isdigit():
|
||||||
|
s += self.as_num(w)
|
||||||
|
# Other identifier
|
||||||
|
else:
|
||||||
|
s += self.as_id(w)
|
||||||
|
# Output as is
|
||||||
|
else:
|
||||||
|
s += ch
|
||||||
|
x += 1
|
||||||
|
self.add_line(s)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
class asmview_t(idaapi.simplecustviewer_t, asm_colorizer_t):
|
||||||
|
def Create(self, fn):
|
||||||
|
# Create the customview
|
||||||
|
if not idaapi.simplecustviewer_t.Create(self, "Viewing file - %s" % os.path.basename(fn)):
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.instruction_list = idautils.GetInstructionList()
|
||||||
|
self.instruction_list.extend(["ret"])
|
||||||
|
self.register_list = idautils.GetRegisterList()
|
||||||
|
self.register_list.extend(["eax", "ebx", "ecx", "edx", "edi", "esi", "ebp", "esp"])
|
||||||
|
|
||||||
|
self.fn = fn
|
||||||
|
if not self.reload_file():
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.id_refresh = self.AddPopupMenu("Refresh")
|
||||||
|
self.id_close = self.AddPopupMenu("Close")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def reload_file(self):
|
||||||
|
if not self.colorize_file(self.fn):
|
||||||
|
self.Close()
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def colorize_file(self, fn):
|
||||||
|
try:
|
||||||
|
f = open(fn, "r")
|
||||||
|
lines = f.readlines()
|
||||||
|
f.close()
|
||||||
|
self.ClearLines()
|
||||||
|
self.colorize(lines)
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def add_line(self, s=None):
|
||||||
|
if not s:
|
||||||
|
s = ""
|
||||||
|
self.AddLine(s)
|
||||||
|
|
||||||
|
def as_comment(self, s):
|
||||||
|
return idaapi.COLSTR(s, idaapi.SCOLOR_RPTCMT)
|
||||||
|
|
||||||
|
def as_id(self, s):
|
||||||
|
t = s.lower()
|
||||||
|
if t in self.register_list:
|
||||||
|
return idaapi.COLSTR(s, idaapi.SCOLOR_REG)
|
||||||
|
elif t in self.instruction_list:
|
||||||
|
return idaapi.COLSTR(s, idaapi.SCOLOR_INSN)
|
||||||
|
else:
|
||||||
|
return s
|
||||||
|
|
||||||
|
def as_string(self, s):
|
||||||
|
return idaapi.COLSTR(s, idaapi.SCOLOR_STRING)
|
||||||
|
|
||||||
|
def as_num(self, s):
|
||||||
|
return idaapi.COLSTR(s, idaapi.SCOLOR_NUMBER)
|
||||||
|
|
||||||
|
def as_directive(self, s):
|
||||||
|
return idaapi.COLSTR(s, idaapi.SCOLOR_KEYWORD)
|
||||||
|
|
||||||
|
def OnPopupMenu(self, menu_id):
|
||||||
|
"""
|
||||||
|
A context (or popup) menu item was executed.
|
||||||
|
@param menu_id: ID previously registered with AddPopupMenu()
|
||||||
|
@return: Boolean
|
||||||
|
"""
|
||||||
|
if self.id_refresh == menu_id:
|
||||||
|
return self.reload_file()
|
||||||
|
elif self.id_close == menu_id:
|
||||||
|
self.Close()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def OnKeydown(self, vkey, shift):
|
||||||
|
"""
|
||||||
|
User pressed a key
|
||||||
|
@param vkey: Virtual key code
|
||||||
|
@param shift: Shift flag
|
||||||
|
@return Boolean. True if you handled the event
|
||||||
|
"""
|
||||||
|
# ESCAPE
|
||||||
|
if vkey == 27:
|
||||||
|
self.Close()
|
||||||
|
elif vkey == ord('H'):
|
||||||
|
lineno = self.GetLineNo()
|
||||||
|
if lineno is not None:
|
||||||
|
line, fg, bg = self.GetLine(lineno)
|
||||||
|
if line and line[0] != idaapi.SCOLOR_INV:
|
||||||
|
s = idaapi.SCOLOR_INV + line + idaapi.SCOLOR_INV
|
||||||
|
self.EditLine(lineno, s, fg, bg)
|
||||||
|
self.Refresh()
|
||||||
|
elif vkey == ord('C'):
|
||||||
|
self.ClearLines()
|
||||||
|
self.Refresh()
|
||||||
|
elif vkey == ord('S'):
|
||||||
|
print "Selection (x1, y1, x2, y2) = ", self.GetSelection()
|
||||||
|
elif vkey == ord('I'):
|
||||||
|
print "Position (line, x, y) = ", self.GetPos(mouse = 0)
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
class asmviewplg(idaapi.plugin_t):
|
||||||
|
flags = idaapi.PLUGIN_KEEP
|
||||||
|
comment = "ASM viewer"
|
||||||
|
help = "This is help"
|
||||||
|
wanted_name = "ASM file viewer"
|
||||||
|
wanted_hotkey = "Alt-F8"
|
||||||
|
def __init__(self):
|
||||||
|
self.view = None
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
return idaapi.PLUGIN_KEEP
|
||||||
|
def run(self, arg):
|
||||||
|
if self.view:
|
||||||
|
self.Close()
|
||||||
|
fn = idc.AskFile(0, "*.asm", "Select ASM file to view")
|
||||||
|
if not fn:
|
||||||
|
return
|
||||||
|
self.view = asmview_t()
|
||||||
|
if not self.view.Create(fn):
|
||||||
|
return
|
||||||
|
self.view.Show()
|
||||||
|
|
||||||
|
def term(self):
|
||||||
|
if self.view:
|
||||||
|
self.view.Close()
|
||||||
|
|
||||||
|
def PLUGIN_ENTRY():
|
||||||
|
return asmviewplg()
|
175
Scripts/CallStackWalk.py
Normal file
175
Scripts/CallStackWalk.py
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
"""
|
||||||
|
|
||||||
|
A script that tries to determine the call stack
|
||||||
|
|
||||||
|
Run the application with the debugger, suspend the debugger, select a thread and finally run the script.
|
||||||
|
|
||||||
|
Copyright (c) 1990-2009 Hex-Rays
|
||||||
|
ALL RIGHTS RESERVED.
|
||||||
|
|
||||||
|
|
||||||
|
v1.0 - initial version
|
||||||
|
v1.0.1 - added stack segment bitness detection, thus works with 64bit processes too
|
||||||
|
"""
|
||||||
|
import idaapi
|
||||||
|
import idc
|
||||||
|
import idautils
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# class to take a copy of a segment_t
|
||||||
|
class Seg():
|
||||||
|
def __init__(self, s):
|
||||||
|
self.startEA = s.startEA
|
||||||
|
self.endEA = s.endEA
|
||||||
|
self.perm = s.perm
|
||||||
|
self.bitness = s.bitness
|
||||||
|
def __cmp__(self, other):
|
||||||
|
return cmp(self.startEA, other.startEA)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# each item described as:
|
||||||
|
# [ delta, [ opcode(s) ] ]
|
||||||
|
#FF10 call d,[eax]
|
||||||
|
#FF5000 call d,[eax][0]
|
||||||
|
#FF9044332211 call d,[eax][011223344]
|
||||||
|
#FF1500000100 call d,[000010000]
|
||||||
|
#FF9300000000 call d,[ebx][0]
|
||||||
|
#FF10 call d,[eax]
|
||||||
|
CallPattern = \
|
||||||
|
[
|
||||||
|
[-2, [0xFF] ],
|
||||||
|
[-3, [0xFF] ],
|
||||||
|
[-5, [0xE8] ],
|
||||||
|
[-6, [0xFF] ],
|
||||||
|
]
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def IsPrevInsnCall(ea):
|
||||||
|
"""
|
||||||
|
Given a return address, this function tries to check if previous instruction
|
||||||
|
is a CALL instruction
|
||||||
|
"""
|
||||||
|
global CallPattern
|
||||||
|
if ea == idaapi.BADADDR or ea < 10:
|
||||||
|
return None
|
||||||
|
|
||||||
|
for delta, opcodes in CallPattern:
|
||||||
|
# assume caller's ea
|
||||||
|
caller = ea + delta
|
||||||
|
# get the bytes
|
||||||
|
bytes = [x for x in GetDataList(caller, len(opcodes), 1)]
|
||||||
|
# do we have a match? is it a call instruction?
|
||||||
|
if bytes == opcodes and idaapi.is_call_insn(caller):
|
||||||
|
return caller
|
||||||
|
return None
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def CallStackWalk(nn):
|
||||||
|
class Result:
|
||||||
|
"""
|
||||||
|
Class holding the result of one call stack item
|
||||||
|
Each call stack item instance has the following attributes:
|
||||||
|
caller = ea of caller
|
||||||
|
displ = display string
|
||||||
|
sp = stack pointer
|
||||||
|
"""
|
||||||
|
def __init__(self, caller, sp):
|
||||||
|
self.caller = caller
|
||||||
|
self.sp = sp
|
||||||
|
f = idaapi.get_func(caller)
|
||||||
|
self.displ = "%08x: " % caller
|
||||||
|
if f:
|
||||||
|
self.displ += idc.GetFunctionName(caller)
|
||||||
|
t = caller - f.startEA
|
||||||
|
if t > 0: self.displ += "+" + hex(t)
|
||||||
|
else:
|
||||||
|
self.displ += hex(caller)
|
||||||
|
self.displ += " [" + hex(sp) + "]"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.displ
|
||||||
|
|
||||||
|
# get stack pointer
|
||||||
|
sp = cpu.Esp
|
||||||
|
seg = idaapi.getseg(sp)
|
||||||
|
if not seg:
|
||||||
|
return (False, "Could not locate stack segment!")
|
||||||
|
|
||||||
|
stack_seg = Seg(seg)
|
||||||
|
word_size = 2 ** (seg.bitness + 1)
|
||||||
|
callers = []
|
||||||
|
sp = cpu.Esp - word_size
|
||||||
|
while sp < stack_seg.endEA:
|
||||||
|
sp += word_size
|
||||||
|
ptr = idautils.GetDataList(sp, 1, word_size).next()
|
||||||
|
seg = idaapi.getseg(ptr)
|
||||||
|
# only accept executable segments
|
||||||
|
if (not seg) or ((seg.perm & idaapi.SEGPERM_EXEC) == 0):
|
||||||
|
continue
|
||||||
|
# try to find caller
|
||||||
|
caller = IsPrevInsnCall(ptr)
|
||||||
|
# we have no recognized caller, skip!
|
||||||
|
if caller is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# do we have a debug name that is near?
|
||||||
|
if nn:
|
||||||
|
ret = nn.find(caller)
|
||||||
|
if ret:
|
||||||
|
ea = ret[0]
|
||||||
|
# function exists?
|
||||||
|
f = idaapi.get_func(ea)
|
||||||
|
if not f:
|
||||||
|
# create function
|
||||||
|
idc.MakeFunction(ea, idaapi.BADADDR)
|
||||||
|
|
||||||
|
# get the flags
|
||||||
|
f = idc.GetFlags(caller)
|
||||||
|
# no code there?
|
||||||
|
if not isCode(f):
|
||||||
|
MakeCode(caller)
|
||||||
|
|
||||||
|
callers.append(Result(caller, sp))
|
||||||
|
#
|
||||||
|
return (True, callers)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Chooser class
|
||||||
|
class CallStackWalkChoose(Choose):
|
||||||
|
def __init__(self, list, title):
|
||||||
|
Choose.__init__(self, list, title)
|
||||||
|
self.width = 250
|
||||||
|
|
||||||
|
def enter(self, n):
|
||||||
|
o = self.list[n-1]
|
||||||
|
idc.Jump(o.caller)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def main():
|
||||||
|
if not idaapi.is_debugger_on():
|
||||||
|
idc.Warning("Please run the process first!")
|
||||||
|
return
|
||||||
|
if idaapi.get_process_state() != -1:
|
||||||
|
idc.Warning("Please suspend the debugger first!")
|
||||||
|
return
|
||||||
|
|
||||||
|
# only avail from IdaPython r232
|
||||||
|
if hasattr(idaapi, "NearestName"):
|
||||||
|
# get all debug names
|
||||||
|
dn = idaapi.get_debug_names(idaapi.cvar.inf.minEA, idaapi.cvar.inf.maxEA)
|
||||||
|
# initiate a nearest name search (using debug names)
|
||||||
|
nn = idaapi.NearestName(dn)
|
||||||
|
else:
|
||||||
|
nn = None
|
||||||
|
|
||||||
|
ret, callstack = CallStackWalk(nn)
|
||||||
|
if ret:
|
||||||
|
title = "Call stack walker (thread %X)" % (GetCurrentThreadId())
|
||||||
|
idaapi.close_chooser(title)
|
||||||
|
c = CallStackWalkChoose(callstack, title)
|
||||||
|
c.choose()
|
||||||
|
else:
|
||||||
|
idc.Warning("Failed to walk the stack:" + callstack)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
main()
|
101
Scripts/DbgCmd.py
Normal file
101
Scripts/DbgCmd.py
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Debugger command prompt with CustomViewers
|
||||||
|
# (c) Hex-Rays
|
||||||
|
#
|
||||||
|
import idaapi
|
||||||
|
import idc
|
||||||
|
from idaapi import simplecustviewer_t
|
||||||
|
|
||||||
|
def SendDbgCommand(cmd):
|
||||||
|
"""Sends a command to the debugger and returns the output string.
|
||||||
|
An exception will be raised if the debugger is not running or the current debugger does not export
|
||||||
|
the 'SendDbgCommand' IDC command.
|
||||||
|
"""
|
||||||
|
s = Eval('SendDbgCommand("%s");' % cmd)
|
||||||
|
if s.startswith("IDC_FAILURE"):
|
||||||
|
raise Exception, "Debugger command is available only when the debugger is active!"
|
||||||
|
return s
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
class dbgcmd_t(simplecustviewer_t):
|
||||||
|
def Create(self):
|
||||||
|
# Form the title
|
||||||
|
title = "Debugger command window"
|
||||||
|
# Create the customview
|
||||||
|
if not simplecustviewer_t.Create(self, title):
|
||||||
|
return False
|
||||||
|
self.last_cmd = ""
|
||||||
|
self.menu_clear = self.AddPopupMenu("Clear")
|
||||||
|
self.menu_cmd = self.AddPopupMenu("New command")
|
||||||
|
|
||||||
|
self.ResetOutput()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def IssueCommand(self):
|
||||||
|
s = idaapi.askstr(0, self.last_cmd, "Please enter a debugger command")
|
||||||
|
if not s:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Save last command
|
||||||
|
self.last_cmd = s
|
||||||
|
|
||||||
|
# Add it using a different color
|
||||||
|
self.AddLine("debugger>" + idaapi.COLSTR(s, idaapi.SCOLOR_VOIDOP))
|
||||||
|
|
||||||
|
try:
|
||||||
|
r = SendDbgCommand(s).split("\n")
|
||||||
|
for s in r:
|
||||||
|
self.AddLine(idaapi.COLSTR(s, idaapi.SCOLOR_LIBNAME))
|
||||||
|
except:
|
||||||
|
self.AddLine(idaapi.COLSTR("Debugger is not active or does not export SendDbgCommand()", idaapi.SCOLOR_ERROR))
|
||||||
|
self.Refresh()
|
||||||
|
|
||||||
|
def ResetOutput(self):
|
||||||
|
self.ClearLines()
|
||||||
|
self.AddLine(idaapi.COLSTR("Please press INS to enter command; X to clear output", idaapi.SCOLOR_AUTOCMT))
|
||||||
|
self.Refresh()
|
||||||
|
|
||||||
|
def OnKeydown(self, vkey, shift):
|
||||||
|
# ESCAPE?
|
||||||
|
if vkey == 27:
|
||||||
|
self.Close()
|
||||||
|
# VK_INSERT
|
||||||
|
elif vkey == 45:
|
||||||
|
self.IssueCommand()
|
||||||
|
elif vkey == ord('X'):
|
||||||
|
self.ResetOutput()
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def OnPopupMenu(self, menu_id):
|
||||||
|
if menu_id == self.menu_clear:
|
||||||
|
self.ResetOutput()
|
||||||
|
elif menu_id == self.menu_cmd:
|
||||||
|
self.IssueCommand()
|
||||||
|
else:
|
||||||
|
# Unhandled
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def show_win():
|
||||||
|
x = dbgcmd_t()
|
||||||
|
if not x.Create():
|
||||||
|
print "Failed to create debugger command line!"
|
||||||
|
return None
|
||||||
|
x.Show()
|
||||||
|
return x
|
||||||
|
|
||||||
|
try:
|
||||||
|
# created already?
|
||||||
|
dbgcmd
|
||||||
|
dbgcmd.Close()
|
||||||
|
del dbgcmd
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
dbgcmd = show_win()
|
||||||
|
if not dbgcmd:
|
||||||
|
del dbgcmd
|
||||||
|
|
105
Scripts/DrvsDispatch.py
Normal file
105
Scripts/DrvsDispatch.py
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
"""
|
||||||
|
|
||||||
|
A script to demonstrate how to send commands to the debugger and then parse and use the output in IDA
|
||||||
|
|
||||||
|
Copyright (c) 1990-2009 Hex-Rays
|
||||||
|
ALL RIGHTS RESERVED.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
from idaapi import Choose
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def CmdDriverList():
|
||||||
|
s = Eval('WinDbgCommand("lm o");')
|
||||||
|
if "IDC_FAILURE" in s: return False
|
||||||
|
return s
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def CmdDrvObj(drvname, flag=2):
|
||||||
|
return Eval('WinDbgCommand("!drvobj %s %d");' % (drvname, flag))
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def CmdReloadForce():
|
||||||
|
s = Eval('WinDbgCommand(".reload /f");')
|
||||||
|
if "IDC_FAILURE" in s: return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# class to hold dispatch entry information
|
||||||
|
class DispatchEntry:
|
||||||
|
def __init__(self, addr, name):
|
||||||
|
self.addr = addr
|
||||||
|
self.name = name
|
||||||
|
def __repr__(self):
|
||||||
|
return "%08X: %s" % (self.addr, self.name)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def GetDriverDispatch():
|
||||||
|
|
||||||
|
# return a list of arrays of the form: [addr, name]
|
||||||
|
ret_list = []
|
||||||
|
|
||||||
|
# build the RE for parsing output from the "lm o" command
|
||||||
|
re_drv = re.compile('^[a-f0-9]+\s+[a-f0-9]+\s+(\S+)', re.I)
|
||||||
|
|
||||||
|
# build the RE for parsing output from the "!drvobj DRV_NAME 2" command
|
||||||
|
re_tbl = re.compile('^\[\d{2}\]\s+IRP_MJ_(\S+)\s+([0-9a-f]+)', re.I)
|
||||||
|
|
||||||
|
# force reloading of module symbols
|
||||||
|
if not CmdReloadForce():
|
||||||
|
print "Could not communicate with WinDbg, make sure the debugger is running!"
|
||||||
|
return None
|
||||||
|
|
||||||
|
# get driver list
|
||||||
|
lm_out = CmdDriverList()
|
||||||
|
if not lm_out:
|
||||||
|
return "Failed to get driver list!"
|
||||||
|
|
||||||
|
# for each line
|
||||||
|
for line in lm_out.split("\n"):
|
||||||
|
# parse
|
||||||
|
r = re_drv.match(line)
|
||||||
|
if not r: continue
|
||||||
|
|
||||||
|
# extract driver name
|
||||||
|
drvname = r.group(1).strip()
|
||||||
|
|
||||||
|
# execute "drvobj" command
|
||||||
|
tbl_out = CmdDrvObj(drvname)
|
||||||
|
|
||||||
|
if not tbl_out:
|
||||||
|
print "Failed to get driver object for", drvname
|
||||||
|
continue
|
||||||
|
|
||||||
|
# for each line
|
||||||
|
for line in tbl_out.split("\n"):
|
||||||
|
# parse
|
||||||
|
r = re_tbl.match(line)
|
||||||
|
if not r: continue
|
||||||
|
disp_addr = int(r.group(2), 16) # convert hex string to number
|
||||||
|
disp_name = "Dispatch" + r.group(1)
|
||||||
|
ret_list.append(DispatchEntry(disp_addr, drvname + "_" + disp_name))
|
||||||
|
|
||||||
|
return ret_list
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Chooser class
|
||||||
|
class DispatchChoose(Choose):
|
||||||
|
def __init__(self, list, title):
|
||||||
|
Choose.__init__(self, list, title)
|
||||||
|
self.width = 250
|
||||||
|
|
||||||
|
def enter(self, n):
|
||||||
|
o = self.list[n-1]
|
||||||
|
idc.Jump(o.addr)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# main
|
||||||
|
r = GetDriverDispatch()
|
||||||
|
if r:
|
||||||
|
c = DispatchChoose(r, "Dispatch table browser")
|
||||||
|
c.choose()
|
||||||
|
else:
|
||||||
|
print "Failed to retrieve dispatchers list!"
|
52
Scripts/ExchainDump.py
Normal file
52
Scripts/ExchainDump.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
"""
|
||||||
|
|
||||||
|
This script shows how to send debugger commands and use the result in IDA
|
||||||
|
|
||||||
|
Copyright (c) 1990-2009 Hex-Rays
|
||||||
|
ALL RIGHTS RESERVED.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import idc
|
||||||
|
import re
|
||||||
|
|
||||||
|
# class to store parsed results
|
||||||
|
class exchain:
|
||||||
|
def __init__(self, m):
|
||||||
|
self.name = m.group(1)
|
||||||
|
self.addr = int(m.group(2), 16)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "%x: %s" % (self.addr, self.name)
|
||||||
|
|
||||||
|
# Chooser class
|
||||||
|
class MyChoose(Choose):
|
||||||
|
def __init__(self, list, title):
|
||||||
|
Choose.__init__(self, list, title)
|
||||||
|
self.width = 250
|
||||||
|
|
||||||
|
def enter(self, n):
|
||||||
|
o = self.list[n-1]
|
||||||
|
idc.Jump(o.addr)
|
||||||
|
|
||||||
|
# main
|
||||||
|
def main():
|
||||||
|
s = idc.Eval('SendDbgCommand("!exchain")')
|
||||||
|
if "IDC_FAILURE" in s:
|
||||||
|
return (False, "Cannot execute the command")
|
||||||
|
|
||||||
|
matches = re.finditer(r'[^:]+: ([^\(]+) \(([^\)]+)\)\n', s)
|
||||||
|
L = []
|
||||||
|
for x in matches:
|
||||||
|
L.append(exchain(x))
|
||||||
|
if not L:
|
||||||
|
return (False, "Nothing to display: Could parse the result!")
|
||||||
|
|
||||||
|
# Get a Choose instance
|
||||||
|
chooser = MyChoose(L, "Exchain choose")
|
||||||
|
# Run the chooser
|
||||||
|
chooser.choose()
|
||||||
|
return (True, "Success!")
|
||||||
|
ok, r = main()
|
||||||
|
if not ok:
|
||||||
|
print r
|
139
Scripts/FindInstructions.py
Normal file
139
Scripts/FindInstructions.py
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
"""
|
||||||
|
FindInstructions.py: A script to help you find desired opcodes/instructions in a database
|
||||||
|
|
||||||
|
The script accepts opcodes and assembly statements (which will be assembled) separated by semicolon
|
||||||
|
|
||||||
|
The general syntax is:
|
||||||
|
find(asm or opcodes, x=Bool, asm_where=ea)
|
||||||
|
|
||||||
|
* Example:
|
||||||
|
find("asm_statement1;asm_statement2;de ea dc 0d e0;asm_statement3;xx yy zz;...")
|
||||||
|
* To filter-out non-executable segments pass x=True
|
||||||
|
find("jmp dword ptr [esp]", x=True)
|
||||||
|
* To specify in which context the instructions should be assembled, pass asm_where=ea:
|
||||||
|
find("jmp dword ptr [esp]", asm_where=here())
|
||||||
|
|
||||||
|
Copyright (c) 1990-2009 Hex-Rays
|
||||||
|
ALL RIGHTS RESERVED.
|
||||||
|
|
||||||
|
v1.0 - initial version
|
||||||
|
"""
|
||||||
|
import idaapi
|
||||||
|
import idautils
|
||||||
|
import idc
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def FindInstructions(instr, asm_where=None):
|
||||||
|
"""
|
||||||
|
Finds instructions/opcodes
|
||||||
|
@return: Returns a tuple(True, [ ea, ... ]) or a tuple(False, "error message")
|
||||||
|
"""
|
||||||
|
if not asm_where:
|
||||||
|
# get first segment
|
||||||
|
asm_where = FirstSeg()
|
||||||
|
if asm_where == idaapi.BADADDR:
|
||||||
|
return (False, "No segments defined")
|
||||||
|
|
||||||
|
# regular expression to distinguish between opcodes and instructions
|
||||||
|
re_opcode = re.compile('^[0-9a-f]{2} *', re.I)
|
||||||
|
|
||||||
|
# split lines
|
||||||
|
lines = instr.split(";")
|
||||||
|
|
||||||
|
# all the assembled buffers (for each instruction)
|
||||||
|
bufs = []
|
||||||
|
for line in lines:
|
||||||
|
if re_opcode.match(line):
|
||||||
|
# convert from hex string to a character list then join the list to form one string
|
||||||
|
buf = ''.join([chr(int(x, 16)) for x in line.split()])
|
||||||
|
else:
|
||||||
|
# assemble the instruction
|
||||||
|
ret, buf = Assemble(asm_where, line)
|
||||||
|
if not ret:
|
||||||
|
return (False, "Failed to assemble:"+line)
|
||||||
|
# add the assembled buffer
|
||||||
|
bufs.append(buf)
|
||||||
|
|
||||||
|
# join the buffer into one string
|
||||||
|
buf = ''.join(bufs)
|
||||||
|
|
||||||
|
# take total assembled instructions length
|
||||||
|
tlen = len(buf)
|
||||||
|
|
||||||
|
# convert from binary string to space separated hex string
|
||||||
|
bin_str = ' '.join(["%02X" % ord(x) for x in buf])
|
||||||
|
|
||||||
|
# find all binary strings
|
||||||
|
print "Searching for: [%s]" % bin_str
|
||||||
|
ea = MinEA()
|
||||||
|
ret = []
|
||||||
|
while True:
|
||||||
|
ea = FindBinary(ea, SEARCH_DOWN, bin_str)
|
||||||
|
if ea == idaapi.BADADDR:
|
||||||
|
break
|
||||||
|
ret.append(ea)
|
||||||
|
Message(".")
|
||||||
|
ea += tlen
|
||||||
|
if not ret:
|
||||||
|
return (False, "Could not match [%s]" % bin_str)
|
||||||
|
Message("\n")
|
||||||
|
return (True, ret)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Chooser class
|
||||||
|
class SearchResultChoose(Choose):
|
||||||
|
def __init__(self, list, title):
|
||||||
|
Choose.__init__(self, list, title)
|
||||||
|
self.width = 250
|
||||||
|
|
||||||
|
def enter(self, n):
|
||||||
|
o = self.list[n-1]
|
||||||
|
Jump(o.ea)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# class to represent the results
|
||||||
|
class SearchResult:
|
||||||
|
def __init__(self, ea):
|
||||||
|
self.ea = ea
|
||||||
|
if not isCode(GetFlags(ea)):
|
||||||
|
MakeCode(ea)
|
||||||
|
t = idaapi.generate_disasm_line(ea)
|
||||||
|
if t:
|
||||||
|
line = idaapi.tag_remove(t)
|
||||||
|
else:
|
||||||
|
line = ""
|
||||||
|
func = GetFunctionName(ea)
|
||||||
|
self.display = hex(ea) + ": "
|
||||||
|
if func:
|
||||||
|
self.display += func + ": "
|
||||||
|
else:
|
||||||
|
n = SegName(ea)
|
||||||
|
if n: self.display += n + ": "
|
||||||
|
self.display += line
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.display
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def find(s=None, x=False, asm_where=None):
|
||||||
|
b, ret = FindInstructions(s, asm_where)
|
||||||
|
if b:
|
||||||
|
# executable segs only?
|
||||||
|
if x:
|
||||||
|
results = []
|
||||||
|
for ea in ret:
|
||||||
|
seg = idaapi.getseg(ea)
|
||||||
|
if (not seg) or (seg.perm & idaapi.SEGPERM_EXEC) == 0:
|
||||||
|
continue
|
||||||
|
results.append(SearchResult(ea))
|
||||||
|
else:
|
||||||
|
results = [SearchResult(ea) for ea in ret]
|
||||||
|
title = "Search result for: [%s]" % s
|
||||||
|
idaapi.close_chooser(title)
|
||||||
|
c = SearchResultChoose(results, title)
|
||||||
|
c.choose()
|
||||||
|
else:
|
||||||
|
print ret
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
print "Please use find('asm_stmt1;xx yy;...', x=Bool,asm_where=ea) to search for instructions or opcodes. Specify x=true to filter out non-executable segments"
|
69
Scripts/ImpRef.py
Normal file
69
Scripts/ImpRef.py
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# This is an example illustrating how to enumerate all addresses
|
||||||
|
# that refer to all imported functions in a given module
|
||||||
|
#
|
||||||
|
# (c) Hex-Rays
|
||||||
|
#
|
||||||
|
|
||||||
|
import idaapi
|
||||||
|
import idc
|
||||||
|
import idautils
|
||||||
|
import re
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def find_imported_funcs(dllname):
|
||||||
|
def imp_cb(ea, name, ord):
|
||||||
|
if not name:
|
||||||
|
name = ''
|
||||||
|
imports.append([ea, name, ord])
|
||||||
|
return True
|
||||||
|
|
||||||
|
imports = []
|
||||||
|
nimps = idaapi.get_import_module_qty()
|
||||||
|
for i in xrange(0, nimps):
|
||||||
|
name = idaapi.get_import_module_name(i)
|
||||||
|
if re.match(dllname, name, re.IGNORECASE) is None:
|
||||||
|
continue
|
||||||
|
idaapi.enum_import_names(i, imp_cb)
|
||||||
|
|
||||||
|
return imports
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def find_import_ref(dllname):
|
||||||
|
imports = find_imported_funcs(dllname)
|
||||||
|
R = dict()
|
||||||
|
for i, (ea, name,_) in enumerate(imports):
|
||||||
|
#print "%x -> %s" % (ea, name)
|
||||||
|
for xref in idautils.XrefsTo(ea):
|
||||||
|
# check if referrer is a thunk
|
||||||
|
ea = xref.frm
|
||||||
|
f = idaapi.get_func(ea)
|
||||||
|
if f and (f.flags & idaapi.FUNC_THUNK) != 0:
|
||||||
|
imports.append([f.startEA, idaapi.get_func_name(f.startEA), 0])
|
||||||
|
#print "\t%x %s: from a thunk, parent added %x" % (ea, name, f.startEA)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# save results
|
||||||
|
if not R.has_key(i):
|
||||||
|
R[i] = []
|
||||||
|
|
||||||
|
R[i].append(ea)
|
||||||
|
|
||||||
|
return (imports, R)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def main():
|
||||||
|
dllname = idc.AskStr('kernel32', "Enter module name")
|
||||||
|
if not dllname:
|
||||||
|
print("Cancelled")
|
||||||
|
return
|
||||||
|
|
||||||
|
imports, R = find_import_ref(dllname)
|
||||||
|
for k, v in R.items():
|
||||||
|
print(imports[k][1])
|
||||||
|
for ea in v:
|
||||||
|
print("\t%x" % ea)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
main()
|
124
Scripts/ImportExportViewer.py
Normal file
124
Scripts/ImportExportViewer.py
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# This is an example illustrating how to:
|
||||||
|
# - enumerate imports
|
||||||
|
# - enumerate entrypoints
|
||||||
|
# - Use PluginForm class
|
||||||
|
# - Use PySide with PluginForm to create a Python UI
|
||||||
|
#
|
||||||
|
# (c) Hex-Rays
|
||||||
|
#
|
||||||
|
import idaapi
|
||||||
|
import idautils
|
||||||
|
from idaapi import PluginForm
|
||||||
|
from PySide import QtGui, QtCore
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
class ImpExpForm_t(PluginForm):
|
||||||
|
|
||||||
|
def imports_names_cb(self, ea, name, ord):
|
||||||
|
self.items.append((ea, '' if not name else name, ord))
|
||||||
|
# True -> Continue enumeration
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def BuildImports(self):
|
||||||
|
tree = {}
|
||||||
|
nimps = idaapi.get_import_module_qty()
|
||||||
|
|
||||||
|
for i in xrange(0, nimps):
|
||||||
|
name = idaapi.get_import_module_name(i)
|
||||||
|
if not name:
|
||||||
|
continue
|
||||||
|
# Create a list for imported names
|
||||||
|
self.items = []
|
||||||
|
|
||||||
|
# Enum imported entries in this module
|
||||||
|
idaapi.enum_import_names(i, self.imports_names_cb)
|
||||||
|
|
||||||
|
if name not in tree:
|
||||||
|
tree[name] = []
|
||||||
|
tree[name].extend(self.items)
|
||||||
|
|
||||||
|
return tree
|
||||||
|
|
||||||
|
|
||||||
|
def BuildExports(self):
|
||||||
|
return list(idautils.Entries())
|
||||||
|
|
||||||
|
|
||||||
|
def PopulateTree(self):
|
||||||
|
# Clear previous items
|
||||||
|
self.tree.clear()
|
||||||
|
|
||||||
|
# Build imports
|
||||||
|
root = QtGui.QTreeWidgetItem(self.tree)
|
||||||
|
root.setText(0, "Imports")
|
||||||
|
|
||||||
|
for dll_name, imp_entries in self.BuildImports().items():
|
||||||
|
imp_dll = QtGui.QTreeWidgetItem(root)
|
||||||
|
imp_dll.setText(0, dll_name)
|
||||||
|
|
||||||
|
for imp_ea, imp_name, imp_ord in imp_entries:
|
||||||
|
item = QtGui.QTreeWidgetItem(imp_dll)
|
||||||
|
item.setText(0, "%s [0x%08x]" %(imp_name, imp_ea))
|
||||||
|
|
||||||
|
|
||||||
|
# Build exports
|
||||||
|
root = QtGui.QTreeWidgetItem(self.tree)
|
||||||
|
root.setText(0, "Exports")
|
||||||
|
|
||||||
|
for exp_i, exp_ord, exp_ea, exp_name in self.BuildExports():
|
||||||
|
item = QtGui.QTreeWidgetItem(root)
|
||||||
|
item.setText(0, "%s [#%d] [0x%08x]" % (exp_name, exp_ord, exp_ea))
|
||||||
|
|
||||||
|
|
||||||
|
def OnCreate(self, form):
|
||||||
|
"""
|
||||||
|
Called when the plugin form is created
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Get parent widget
|
||||||
|
self.parent = self.FormToPySideWidget(form)
|
||||||
|
|
||||||
|
# Create tree control
|
||||||
|
self.tree = QtGui.QTreeWidget()
|
||||||
|
self.tree.setHeaderLabels(("Names",))
|
||||||
|
self.tree.setColumnWidth(0, 100)
|
||||||
|
|
||||||
|
# Create layout
|
||||||
|
layout = QtGui.QVBoxLayout()
|
||||||
|
layout.addWidget(self.tree)
|
||||||
|
|
||||||
|
self.PopulateTree()
|
||||||
|
# Populate PluginForm
|
||||||
|
self.parent.setLayout(layout)
|
||||||
|
|
||||||
|
|
||||||
|
def OnClose(self, form):
|
||||||
|
"""
|
||||||
|
Called when the plugin form is closed
|
||||||
|
"""
|
||||||
|
global ImpExpForm
|
||||||
|
del ImpExpForm
|
||||||
|
print "Closed"
|
||||||
|
|
||||||
|
|
||||||
|
def Show(self):
|
||||||
|
"""Creates the form is not created or focuses it if it was"""
|
||||||
|
return PluginForm.Show(self,
|
||||||
|
"Imports / Exports viewer",
|
||||||
|
options = PluginForm.FORM_PERSIST)
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
def main():
|
||||||
|
global ImpExpForm
|
||||||
|
|
||||||
|
try:
|
||||||
|
ImpExpForm
|
||||||
|
except:
|
||||||
|
ImpExpForm = ImpExpForm_t()
|
||||||
|
|
||||||
|
ImpExpForm.Show()
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
main()
|
85
Scripts/PteDump.py
Normal file
85
Scripts/PteDump.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import idaapi
|
||||||
|
import idc
|
||||||
|
from idaapi import Choose2
|
||||||
|
|
||||||
|
def parse_pte(str):
|
||||||
|
try:
|
||||||
|
parse_pte.re
|
||||||
|
except:
|
||||||
|
parse_pte.re = re.compile('PDE at ([0-9a-f]+)\s*PTE at ([0-9a-f]+)\ncontains ([0-9a-f]+)\s*contains ([0-9a-f]+)\npfn ([0-9]+)\s*([^ ]+)\s*pfn ([0-9a-f]+)\s*([^\r\n]+)', re.I | re.M)
|
||||||
|
parse_pte.items = ('pde', 'pte', 'pdec', 'ptec', 'pdepfn', 'pdepfns', 'ptepfn', 'ptepfns')
|
||||||
|
|
||||||
|
m = parse_pte.re.search(s)
|
||||||
|
r = {}
|
||||||
|
for i in range(0, len(parse_pte.items)):
|
||||||
|
r[parse_pte.items[i]] = m.group(i+1)
|
||||||
|
return r
|
||||||
|
|
||||||
|
class MyChoose2(Choose2):
|
||||||
|
|
||||||
|
def __init__(self, title, ea1, ea2):
|
||||||
|
Choose2.__init__(self, title, [ ["VA", 10], ["PTE attr", 30] ])
|
||||||
|
self.ea1 = ea1
|
||||||
|
self.ea2 = ea2
|
||||||
|
self.n = 0
|
||||||
|
self.icon = 5
|
||||||
|
self.items = []
|
||||||
|
self.Refresh()
|
||||||
|
self.selcount = 0
|
||||||
|
|
||||||
|
def OnGetLine(self, n):
|
||||||
|
print("getline %d" % n)
|
||||||
|
return self.items[n]
|
||||||
|
|
||||||
|
def OnGetSize(self):
|
||||||
|
n = len(self.items)
|
||||||
|
self.Refresh()
|
||||||
|
return n
|
||||||
|
|
||||||
|
def OnRefresh(self, n):
|
||||||
|
print("refresh %d" % n)
|
||||||
|
return n
|
||||||
|
|
||||||
|
def Refresh(self):
|
||||||
|
items = []
|
||||||
|
PG = 0x1000
|
||||||
|
ea1 = self.ea1
|
||||||
|
npages = (self.ea2 - ea1) / PG
|
||||||
|
for i in range(npages):
|
||||||
|
r = idc.SendDbgCommand("!pte %x" % ea1)
|
||||||
|
if not r:
|
||||||
|
return False
|
||||||
|
r = parse_pte(r)
|
||||||
|
items.append([hex(ea1), r['ptepfns']])
|
||||||
|
ea1 += PG
|
||||||
|
|
||||||
|
self.items = items
|
||||||
|
print(self.items)
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def Execute(ea1, ea2):
|
||||||
|
c = MyChoose2("PTE Viewer [%x..%x]" % (ea1, ea2), ea1, ea2)
|
||||||
|
return (c, c.Show())
|
||||||
|
|
||||||
|
|
||||||
|
def DumpPTE(ea1, ea2):
|
||||||
|
items = []
|
||||||
|
PG = 0x1000
|
||||||
|
npages = (ea2 - ea1) / PG
|
||||||
|
for i in range(npages):
|
||||||
|
r = idc.SendDbgCommand("!pte %x" % ea1)
|
||||||
|
if not r:
|
||||||
|
return False
|
||||||
|
print r
|
||||||
|
r = parse_pte(r)
|
||||||
|
print("VA: %08X PTE: %s PDE: %s" % (ea1, r['ptepfns'], r['pdepfns']))
|
||||||
|
ea1 += PG
|
||||||
|
|
||||||
|
def DumpSegPTE(ea):
|
||||||
|
DumpPTE(idc.SegStart(ea), idc.SegEnd(ea))
|
||||||
|
|
||||||
|
DumpSegPTE(here())
|
||||||
|
|
||||||
|
#MyChoose2.Execute(0xF718F000, 0xF718F000+0x1000)
|
||||||
|
|
149
Scripts/SEHGraph.py
Normal file
149
Scripts/SEHGraph.py
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
"""
|
||||||
|
|
||||||
|
A script that graphs all the exception handlers in a given process
|
||||||
|
|
||||||
|
It will be easy to see what thread uses what handler and what handlers are commonly used between threads
|
||||||
|
|
||||||
|
Copyright (c) 1990-2009 Hex-Rays
|
||||||
|
ALL RIGHTS RESERVED.
|
||||||
|
|
||||||
|
|
||||||
|
v1.0 - initial version
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import idaapi
|
||||||
|
import idautils
|
||||||
|
import idc
|
||||||
|
|
||||||
|
from idaapi import GraphViewer
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Since Windbg debug module does not support get_thread_sreg_base()
|
||||||
|
# we will call the debugger engine "dg" command and parse its output
|
||||||
|
def WindbgGetRegBase(tid):
|
||||||
|
s = idc.Eval('WinDbgCommand("dg %x")' % cpu.fs)
|
||||||
|
if "IDC_FAILURE" in s:
|
||||||
|
return 0
|
||||||
|
m = re.compile("[0-9a-f]{4} ([0-9a-f]{8})")
|
||||||
|
t = m.match(s.split('\n')[-2])
|
||||||
|
if not t:
|
||||||
|
return 0
|
||||||
|
return int(t.group(1), 16)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def GetFsBase(tid):
|
||||||
|
idc.SelectThread(tid)
|
||||||
|
base = idaapi.dbg_get_thread_sreg_base(tid, cpu.fs)
|
||||||
|
if base != 0:
|
||||||
|
return base
|
||||||
|
return WindbgGetRegBase(tid)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Walks the SEH chain and returns a list of handlers
|
||||||
|
def GetExceptionChain(tid):
|
||||||
|
fs_base = GetFsBase(tid)
|
||||||
|
exc_rr = Dword(fs_base)
|
||||||
|
result = []
|
||||||
|
while exc_rr != 0xffffffff:
|
||||||
|
prev = Dword(exc_rr)
|
||||||
|
handler = Dword(exc_rr + 4)
|
||||||
|
exc_rr = prev
|
||||||
|
result.append(handler)
|
||||||
|
return result
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
class SEHGraph(GraphViewer):
|
||||||
|
def __init__(self, title, result):
|
||||||
|
GraphViewer.__init__(self, title)
|
||||||
|
self.result = result
|
||||||
|
self.names = {} # ea -> name
|
||||||
|
|
||||||
|
def OnRefresh(self):
|
||||||
|
self.Clear()
|
||||||
|
addr_id = {}
|
||||||
|
|
||||||
|
for (tid, chain) in self.result.items():
|
||||||
|
# Each node data will contain a tuple of the form: (Boolean->Is_thread, Int->Value, String->Label)
|
||||||
|
# For threads the is_thread will be true and the value will hold the thread id
|
||||||
|
# For exception handlers, is_thread=False and Value=Handler address
|
||||||
|
|
||||||
|
# Add the thread node
|
||||||
|
id_parent = self.AddNode( (True, tid, "Thread %X" % tid) )
|
||||||
|
|
||||||
|
# Add each handler
|
||||||
|
for handler in chain:
|
||||||
|
# Check if a function is created at the handler's address
|
||||||
|
f = idaapi.get_func(handler)
|
||||||
|
if not f:
|
||||||
|
# create function
|
||||||
|
idc.MakeFunction(handler, idaapi.BADADDR)
|
||||||
|
|
||||||
|
# Node label is function name or address
|
||||||
|
s = GetFunctionName(handler)
|
||||||
|
if not s:
|
||||||
|
s = "%x" % handler
|
||||||
|
|
||||||
|
# cache name
|
||||||
|
self.names[handler] = s
|
||||||
|
|
||||||
|
# Get the node id given the handler address
|
||||||
|
# We use an addr -> id dictionary so that similar addresses get similar node id
|
||||||
|
if not addr_id.has_key(handler):
|
||||||
|
id = self.AddNode( (False, handler, s) )
|
||||||
|
addr_id[handler] = id # add this ID
|
||||||
|
else:
|
||||||
|
id = addr_id[handler]
|
||||||
|
|
||||||
|
# Link handlers to each other
|
||||||
|
self.AddEdge(id_parent, id)
|
||||||
|
id_parent = id
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def OnGetText(self, node_id):
|
||||||
|
is_thread, value, label = self[node_id]
|
||||||
|
if is_thread:
|
||||||
|
return (label, 0xff00f0)
|
||||||
|
return label
|
||||||
|
|
||||||
|
def OnDblClick(self, node_id):
|
||||||
|
is_thread, value, label = self[node_id]
|
||||||
|
if is_thread:
|
||||||
|
idc.SelectThread(value)
|
||||||
|
self.Show()
|
||||||
|
s = "SEH chain for " + hex(value)
|
||||||
|
t = "-" * len(s)
|
||||||
|
print t
|
||||||
|
print s
|
||||||
|
print t
|
||||||
|
for handler in self.result[value]:
|
||||||
|
print "%x: %s" % (handler, self.names[handler])
|
||||||
|
print t
|
||||||
|
else:
|
||||||
|
idc.Jump(value)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def main():
|
||||||
|
if not idaapi.dbg_can_query():
|
||||||
|
print "The debugger must be active and suspended before using this script!"
|
||||||
|
return
|
||||||
|
|
||||||
|
# Save current thread id
|
||||||
|
tid = GetCurrentThreadId()
|
||||||
|
|
||||||
|
# Iterate through all function instructions and take only call instructions
|
||||||
|
result = {}
|
||||||
|
for tid in idautils.Threads():
|
||||||
|
result[tid] = GetExceptionChain(tid)
|
||||||
|
|
||||||
|
# Restore previously selected thread
|
||||||
|
idc.SelectThread(tid)
|
||||||
|
|
||||||
|
# Build the graph
|
||||||
|
g = SEHGraph("SEH graph", result)
|
||||||
|
g.Show()
|
||||||
|
|
||||||
|
main()
|
70
Scripts/VaDump.py
Normal file
70
Scripts/VaDump.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
"""
|
||||||
|
|
||||||
|
This script shows how to send debugger commands and use the result in IDA
|
||||||
|
|
||||||
|
Copyright (c) 1990-2009 Hex-Rays
|
||||||
|
ALL RIGHTS RESERVED.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import idc
|
||||||
|
from idaapi import Choose
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
# class to store parsed results
|
||||||
|
class memva:
|
||||||
|
def __init__(self, m):
|
||||||
|
self.base = int(m.group(1), 16)
|
||||||
|
self.regionsize = int(m.group(2), 16)
|
||||||
|
self.state = int(m.group(3), 16)
|
||||||
|
self.statestr = m.group(4).strip()
|
||||||
|
self.protect = int(m.group(5), 16)
|
||||||
|
self.protectstr = m.group(6).strip()
|
||||||
|
if m.group(7):
|
||||||
|
self.type = int(m.group(8), 16)
|
||||||
|
self.typestr = m.group(9).strip()
|
||||||
|
else:
|
||||||
|
self.type = 0
|
||||||
|
self.typestr = ""
|
||||||
|
def __str__(self):
|
||||||
|
return "(Base %08X; RegionSize: %08X; State: %08X/%10s; protect: %08X/%10s; type: %08X/%10s)" % (
|
||||||
|
self.base, self.regionsize, self.state,
|
||||||
|
self.statestr, self.protect,
|
||||||
|
self.protectstr, self.type, self.typestr)
|
||||||
|
|
||||||
|
# Chooser class
|
||||||
|
class MemChoose(Choose):
|
||||||
|
def __init__(self, list, title):
|
||||||
|
Choose.__init__(self, list, title)
|
||||||
|
self.width = 250
|
||||||
|
|
||||||
|
def enter(self, n):
|
||||||
|
o = self.list[n-1]
|
||||||
|
idc.Jump(o.base)
|
||||||
|
|
||||||
|
# main
|
||||||
|
def main():
|
||||||
|
s = idc.Eval('SendDbgCommand("!vadump")')
|
||||||
|
if "IDC_FAILURE" in s:
|
||||||
|
return (False, "Cannot execute the command")
|
||||||
|
|
||||||
|
matches = re.finditer(r'BaseAddress:\s*?(\w+?)\n' \
|
||||||
|
+'RegionSize:\s*?(\w*?)\n' \
|
||||||
|
+'State:\s*?(\w*?)\s*?(\w*?)\n' \
|
||||||
|
+'Protect:\s*?(\w*?)\s*?(\w*?)\n' \
|
||||||
|
+'(Type:\s*?(\w*?)\s*?(\w*?)\n)*', s)
|
||||||
|
L = []
|
||||||
|
for x in matches:
|
||||||
|
L.append(memva(x))
|
||||||
|
if not L:
|
||||||
|
return (False, "Nothing to display: Could not parse the result!")
|
||||||
|
|
||||||
|
# Get a Choose instance
|
||||||
|
chooser = MemChoose(L, "Memory choose")
|
||||||
|
# Run the chooser
|
||||||
|
chooser.choose()
|
||||||
|
return (True, "Success!")
|
||||||
|
r = main()
|
||||||
|
if not r[0]:
|
||||||
|
print r[1]
|
68
Scripts/msdnapihelp.py
Normal file
68
Scripts/msdnapihelp.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
"""
|
||||||
|
User contributed script: MSDN API HELP plugin
|
||||||
|
|
||||||
|
This script fetches the API reference (from MSDN) of a given highlighted identifier
|
||||||
|
and returns the results in a new web browser page.
|
||||||
|
|
||||||
|
This script depends on the feedparser package: http://code.google.com/p/feedparser/
|
||||||
|
|
||||||
|
10/05/2010
|
||||||
|
- initial version
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import idaapi
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
class msdnapihelp_plugin_t(idaapi.plugin_t):
|
||||||
|
flags = idaapi.PLUGIN_UNL
|
||||||
|
comment = "Online MSDN API Help"
|
||||||
|
help = "Help me"
|
||||||
|
wanted_name = "MSDN API Help"
|
||||||
|
wanted_hotkey = "F3"
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
return idaapi.PLUGIN_OK
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def sanitize_name(name):
|
||||||
|
t = idaapi.FUNC_IMPORT_PREFIX
|
||||||
|
if name.startswith(t):
|
||||||
|
return name[len(t):]
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
def run(self, arg):
|
||||||
|
# Get the highlighted identifier
|
||||||
|
id = idaapi.get_highlighted_identifier()
|
||||||
|
if not id:
|
||||||
|
print "No identifier was highlighted"
|
||||||
|
return
|
||||||
|
|
||||||
|
import webbrowser
|
||||||
|
|
||||||
|
try:
|
||||||
|
import feedparser
|
||||||
|
except:
|
||||||
|
idaapi.warning('Feedparser package not installed')
|
||||||
|
return
|
||||||
|
|
||||||
|
id = self.sanitize_name(id)
|
||||||
|
print "Looking up '%s' in MSDN online" % id
|
||||||
|
d = feedparser.parse("http://social.msdn.microsoft.com/Search/Feed.aspx?locale=en-us&format=RSS&Query=%s" % id)
|
||||||
|
if len(d['entries']) > 0:
|
||||||
|
url = d['entries'][0].link
|
||||||
|
webbrowser.open_new_tab(url)
|
||||||
|
else:
|
||||||
|
print "API documentation not found for: %s" % id
|
||||||
|
|
||||||
|
|
||||||
|
def term(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
def PLUGIN_ENTRY():
|
||||||
|
return msdnapihelp_plugin_t()
|
16
build.py
16
build.py
@ -24,7 +24,7 @@ from distutils import sysconfig
|
|||||||
VERBOSE = True
|
VERBOSE = True
|
||||||
|
|
||||||
IDA_MAJOR_VERSION = 6
|
IDA_MAJOR_VERSION = 6
|
||||||
IDA_MINOR_VERSION = 0
|
IDA_MINOR_VERSION = 1
|
||||||
|
|
||||||
if 'IDA' in os.environ:
|
if 'IDA' in os.environ:
|
||||||
IDA_SDK = os.environ['IDA']
|
IDA_SDK = os.environ['IDA']
|
||||||
@ -35,8 +35,8 @@ else:
|
|||||||
|
|
||||||
# IDAPython version
|
# IDAPython version
|
||||||
VERSION_MAJOR = 1
|
VERSION_MAJOR = 1
|
||||||
VERSION_MINOR = 4
|
VERSION_MINOR = 5
|
||||||
VERSION_PATCH = 3
|
VERSION_PATCH = 0
|
||||||
|
|
||||||
# Determine Python version
|
# Determine Python version
|
||||||
PYTHON_MAJOR_VERSION = int(platform.python_version()[0])
|
PYTHON_MAJOR_VERSION = int(platform.python_version()[0])
|
||||||
@ -68,6 +68,7 @@ BINDIST_MANIFEST = [
|
|||||||
"CHANGES.txt",
|
"CHANGES.txt",
|
||||||
"AUTHORS.txt",
|
"AUTHORS.txt",
|
||||||
"STATUS.txt",
|
"STATUS.txt",
|
||||||
|
"python.cfg",
|
||||||
"docs/notes.txt",
|
"docs/notes.txt",
|
||||||
"examples/chooser.py",
|
"examples/chooser.py",
|
||||||
"examples/colours.py",
|
"examples/colours.py",
|
||||||
@ -91,6 +92,8 @@ BINDIST_MANIFEST = [
|
|||||||
"examples/ex_prefix_plugin.py",
|
"examples/ex_prefix_plugin.py",
|
||||||
"examples/ex_pyside.py",
|
"examples/ex_pyside.py",
|
||||||
"examples/ex_pyqt.py",
|
"examples/ex_pyqt.py",
|
||||||
|
"examples/ex_askusingform.py",
|
||||||
|
"examples/ex_uihook.py",
|
||||||
"examples/ex_imports.py"
|
"examples/ex_imports.py"
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -100,6 +103,7 @@ SRCDIST_MANIFEST = [
|
|||||||
"python.cpp",
|
"python.cpp",
|
||||||
"basetsd.h",
|
"basetsd.h",
|
||||||
"build.py",
|
"build.py",
|
||||||
|
"python.cfg",
|
||||||
"swig/allins.i",
|
"swig/allins.i",
|
||||||
"swig/area.i",
|
"swig/area.i",
|
||||||
"swig/auto.i",
|
"swig/auto.i",
|
||||||
@ -309,7 +313,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
|
|||||||
platform_macros = [ "__LINUX__" ]
|
platform_macros = [ "__LINUX__" ]
|
||||||
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "lib"
|
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "lib"
|
||||||
python_library = "-lpython%d.%d" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION)
|
python_library = "-lpython%d.%d" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION)
|
||||||
ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "gcc64.lnx" or "gcc32.lnx")
|
ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "x86_linux_gcc_64" or "x86_linux_gcc_32")
|
||||||
ida_lib = ""
|
ida_lib = ""
|
||||||
extra_link_parameters = ""
|
extra_link_parameters = ""
|
||||||
# Platform-specific settings for the Windows build
|
# Platform-specific settings for the Windows build
|
||||||
@ -318,7 +322,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
|
|||||||
platform_macros = [ "__NT__" ]
|
platform_macros = [ "__NT__" ]
|
||||||
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "libs"
|
python_libpath = sysconfig.EXEC_PREFIX + os.sep + "libs"
|
||||||
python_library = "python%d%d.lib" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION)
|
python_library = "python%d%d.lib" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION)
|
||||||
ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "vc.w64" or "vc.w32")
|
ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "x86_win_vc_64" or "x86_win_vc_32")
|
||||||
ida_lib = "ida.lib"
|
ida_lib = "ida.lib"
|
||||||
SWIG_OPTIONS += " -D__NT__ "
|
SWIG_OPTIONS += " -D__NT__ "
|
||||||
extra_link_parameters = ""
|
extra_link_parameters = ""
|
||||||
@ -329,7 +333,7 @@ def build_plugin(platform, idasdkdir, plugin_name, ea64):
|
|||||||
platform_macros = [ "__MAC__" ]
|
platform_macros = [ "__MAC__" ]
|
||||||
python_libpath = "."
|
python_libpath = "."
|
||||||
python_library = "-framework Python"
|
python_library = "-framework Python"
|
||||||
ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "gcc64.mac64" or "gcc32.mac")
|
ida_libpath = os.path.join(idasdkdir, "lib", ea64 and "x86_mac_gcc_64" or "x86_mac_gcc_32")
|
||||||
ida_lib = ea64 and "-lida64" or "-lida"
|
ida_lib = ea64 and "-lida64" or "-lida"
|
||||||
extra_link_parameters = ""
|
extra_link_parameters = ""
|
||||||
|
|
||||||
|
@ -7,16 +7,17 @@
|
|||||||
#
|
#
|
||||||
from idaapi import *
|
from idaapi import *
|
||||||
|
|
||||||
# Get current ea
|
def main():
|
||||||
ea = get_screen_ea()
|
# Get current ea
|
||||||
|
ea = get_screen_ea()
|
||||||
|
|
||||||
# Get segment class
|
# Get segment class
|
||||||
seg = getseg(ea)
|
seg = getseg(ea)
|
||||||
|
|
||||||
# Loop from segment start to end
|
# Loop from segment start to end
|
||||||
func = get_func(seg.startEA)
|
func = get_next_func(seg.startEA)
|
||||||
|
seg_end = seg.endEA
|
||||||
while func != None and func.startEA < seg.endEA:
|
while func is not None and func.startEA < seg_end:
|
||||||
funcea = func.startEA
|
funcea = func.startEA
|
||||||
print "Function %s at 0x%x" % (GetFunctionName(funcea), funcea)
|
print "Function %s at 0x%x" % (GetFunctionName(funcea), funcea)
|
||||||
|
|
||||||
@ -27,3 +28,6 @@ while func != None and func.startEA < seg.endEA:
|
|||||||
ref = get_next_cref_to(funcea, ref)
|
ref = get_next_cref_to(funcea, ref)
|
||||||
|
|
||||||
func = get_next_func(funcea)
|
func = get_next_func(funcea)
|
||||||
|
|
||||||
|
|
||||||
|
main()
|
@ -7,14 +7,21 @@
|
|||||||
#
|
#
|
||||||
from idautils import *
|
from idautils import *
|
||||||
|
|
||||||
# Get current ea
|
def main():
|
||||||
ea = ScreenEA()
|
# Get current ea
|
||||||
|
ea = ScreenEA()
|
||||||
|
if ea == idaapi.BADADDR:
|
||||||
|
print("Could not get get_screen_ea()")
|
||||||
|
return
|
||||||
|
|
||||||
# Loop from start to end in the current segment
|
# Loop from start to end in the current segment
|
||||||
for funcea in Functions(SegStart(ea), SegEnd(ea)):
|
for funcea in Functions(SegStart(ea), SegEnd(ea)):
|
||||||
print "Function %s at 0x%x" % (GetFunctionName(funcea), funcea)
|
print("Function %s at 0x%x" % (GetFunctionName(funcea), funcea))
|
||||||
|
|
||||||
# Find all code references to funcea
|
# Find all code references to funcea
|
||||||
for ref in CodeRefsTo(funcea, 1):
|
for ref in CodeRefsTo(funcea, 1):
|
||||||
print " called from %s(0x%x)" % (GetFunctionName(ref), ref)
|
print(" called from %s(0x%x)" % (GetFunctionName(ref), ref))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__=='__main__':
|
||||||
|
main()
|
@ -1,18 +1,18 @@
|
|||||||
import idaapi
|
import idaapi
|
||||||
|
|
||||||
def cb(*args):
|
def cb(*args):
|
||||||
print "Callback called!"
|
print("Callback called!")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if ctx:
|
ctx
|
||||||
idaapi.del_menu_item(ctx)
|
idaapi.del_menu_item(ctx)
|
||||||
except:
|
print("Menu removed")
|
||||||
pass
|
|
||||||
|
|
||||||
ctx = idaapi.add_menu_item("Search/", "X", "", 0, cb, tuple("hello world"))
|
|
||||||
if ctx is None:
|
|
||||||
print "Failed to add menu!"
|
|
||||||
del ctx
|
del ctx
|
||||||
else:
|
except:
|
||||||
print "Menu added successfully!"
|
ctx = idaapi.add_menu_item("Search/", "X", "", 0, cb, tuple("hello world"))
|
||||||
|
if ctx is None:
|
||||||
|
print("Failed to add menu!")
|
||||||
|
del ctx
|
||||||
|
else:
|
||||||
|
print("Menu added successfully. Run the script again to delete the menu")
|
221
examples/ex_askusingform.py
Normal file
221
examples/ex_askusingform.py
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# This is an example illustrating how to use the Form class
|
||||||
|
# (c) Hex-Rays
|
||||||
|
#
|
||||||
|
from idaapi import Form
|
||||||
|
|
||||||
|
#<pycode(ex_askusingform)>
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
class TestEmbeddedChooserClass(Choose2):
|
||||||
|
"""
|
||||||
|
A simple chooser to be used as an embedded chooser
|
||||||
|
"""
|
||||||
|
def __init__(self, title, nb = 5, flags=0):
|
||||||
|
Choose2.__init__(self,
|
||||||
|
title,
|
||||||
|
[ ["Address", 10], ["Name", 30] ],
|
||||||
|
embedded=True, width=30, height=20, flags=flags)
|
||||||
|
self.n = 0
|
||||||
|
self.items = [ self.make_item() for x in xrange(0, nb+1) ]
|
||||||
|
self.icon = 5
|
||||||
|
self.selcount = 0
|
||||||
|
|
||||||
|
def make_item(self):
|
||||||
|
r = [str(self.n), "func_%04d" % self.n]
|
||||||
|
self.n += 1
|
||||||
|
return r
|
||||||
|
|
||||||
|
def OnClose(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def OnGetLine(self, n):
|
||||||
|
print("getline %d" % n)
|
||||||
|
return self.items[n]
|
||||||
|
|
||||||
|
def OnGetSize(self):
|
||||||
|
n = len(self.items)
|
||||||
|
print("getsize -> %d" % n)
|
||||||
|
return n
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
class MyForm(Form):
|
||||||
|
def __init__(self):
|
||||||
|
self.invert = False
|
||||||
|
self.EChooser = TestEmbeddedChooserClass("E1", flags=Choose2.CH_MULTI)
|
||||||
|
Form.__init__(self, r"""STARTITEM {id:rNormal}
|
||||||
|
BUTTON YES* Yeah
|
||||||
|
BUTTON NO Nope
|
||||||
|
BUTTON CANCEL Nevermind
|
||||||
|
Form Test
|
||||||
|
|
||||||
|
{FormChangeCb}
|
||||||
|
This is a string: +{cStr1}+
|
||||||
|
This is an address: +{cAddr1}+
|
||||||
|
|
||||||
|
Escape\{control}
|
||||||
|
This is a string: '{cStr2}'
|
||||||
|
This is a number: {cVal1}
|
||||||
|
|
||||||
|
<#Hint1#Enter name:{iStr1}>
|
||||||
|
<#Hint2#Select color:{iColor1}>
|
||||||
|
Browse test
|
||||||
|
<#Select a file to open#Browse to open:{iFileOpen}>
|
||||||
|
<#Select a file to save#Browse to save:{iFileSave}>
|
||||||
|
<#Select dir#Browse for dir:{iDir}>
|
||||||
|
Type
|
||||||
|
<#Select type#Write a type:{iType}>
|
||||||
|
Numbers
|
||||||
|
<##Enter a selector value:{iSegment}>
|
||||||
|
<##Enter a raw hex:{iRawHex}>
|
||||||
|
<##Enter a character:{iChar}>
|
||||||
|
<##Enter an address:{iAddr}>
|
||||||
|
Button test
|
||||||
|
<##Button1:{iButton1}> <##Button2:{iButton2}>
|
||||||
|
|
||||||
|
Check boxes:
|
||||||
|
<Error output:{rError}>
|
||||||
|
<Normal output:{rNormal}>
|
||||||
|
<Warnings:{rWarnings}>{cGroup1}>
|
||||||
|
|
||||||
|
Radio boxes:
|
||||||
|
<Green:{rGreen}>
|
||||||
|
<Red:{rRed}>
|
||||||
|
<Blue:{rBlue}>{cGroup2}>
|
||||||
|
<Embedded chooser:{cEChooser}>
|
||||||
|
The end!
|
||||||
|
""", {
|
||||||
|
'cStr1': Form.StringLabel("Hello"),
|
||||||
|
'cStr2': Form.StringLabel("StringTest"),
|
||||||
|
'cAddr1': Form.NumericLabel(0x401000, Form.FT_ADDR),
|
||||||
|
'cVal1' : Form.NumericLabel(99, Form.FT_HEX),
|
||||||
|
'iStr1': Form.StringInput(),
|
||||||
|
'iColor1': Form.ColorInput(),
|
||||||
|
'iFileOpen': Form.FileInput(open=True),
|
||||||
|
'iFileSave': Form.FileInput(save=True),
|
||||||
|
'iDir': Form.DirInput(),
|
||||||
|
'iType': Form.StringInput(tp=Form.FT_TYPE),
|
||||||
|
'iSegment': Form.NumericInput(tp=Form.FT_SEG),
|
||||||
|
'iRawHex': Form.NumericInput(tp=Form.FT_RAWHEX),
|
||||||
|
'iAddr': Form.NumericInput(tp=Form.FT_ADDR),
|
||||||
|
'iChar': Form.NumericInput(tp=Form.FT_CHAR),
|
||||||
|
'iButton1': Form.ButtonInput(self.OnButton1),
|
||||||
|
'iButton2': Form.ButtonInput(self.OnButton2),
|
||||||
|
'cGroup1': Form.ChkGroupControl(("rNormal", "rError", "rWarnings")),
|
||||||
|
'cGroup2': Form.RadGroupControl(("rRed", "rGreen", "rBlue")),
|
||||||
|
'FormChangeCb': Form.FormChangeCb(self.OnFormChange),
|
||||||
|
'cEChooser' : Form.EmbeddedChooserControl(self.EChooser)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def OnButton1(self, code=0):
|
||||||
|
print("Button1 pressed")
|
||||||
|
|
||||||
|
|
||||||
|
def OnButton2(self, code=0):
|
||||||
|
print("Button2 pressed")
|
||||||
|
|
||||||
|
|
||||||
|
def OnFormChange(self, fid):
|
||||||
|
if fid == self.iButton1.id:
|
||||||
|
print("Button1 fchg;inv=%s" % self.invert)
|
||||||
|
self.SetFocusedField(self.rNormal.id)
|
||||||
|
self.EnableField(self.rError.id, self.invert)
|
||||||
|
self.invert = not self.invert
|
||||||
|
elif fid == self.iButton2.id:
|
||||||
|
g1 = self.GetControlValue(self.cGroup1)
|
||||||
|
g2 = self.GetControlValue(self.cGroup2)
|
||||||
|
d = self.GetControlValue(self.iDir)
|
||||||
|
f = self.GetControlValue(self.iFileOpen)
|
||||||
|
print("cGroup2:%x;Dir=%s;fopen=%s;cGroup1:%x" % (g1, d, f, g2))
|
||||||
|
elif fid == self.cEChooser.id:
|
||||||
|
l = self.GetControlValue(self.cEChooser)
|
||||||
|
print("Chooser: %s" % l)
|
||||||
|
else:
|
||||||
|
print(">>fid:%d" % fid)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
def stdalone_main():
|
||||||
|
f = MyForm()
|
||||||
|
f, args = f.Compile()
|
||||||
|
print args[0]
|
||||||
|
print args[1:]
|
||||||
|
f.rNormal.checked = True
|
||||||
|
f.rWarnings.checked = True
|
||||||
|
print hex(f.cGroup1.value)
|
||||||
|
|
||||||
|
f.rGreen.selected = True
|
||||||
|
print f.cGroup2.value
|
||||||
|
print "Title: '%s'" % f.title
|
||||||
|
|
||||||
|
f.Free()
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
def ida_main():
|
||||||
|
# Create form
|
||||||
|
global f
|
||||||
|
f = MyForm()
|
||||||
|
|
||||||
|
# Compile (in order to populate the controls)
|
||||||
|
f.Compile()
|
||||||
|
|
||||||
|
f.iColor1.value = 0x5bffff
|
||||||
|
f.iDir.value = os.getcwd()
|
||||||
|
f.rNormal.checked = True
|
||||||
|
f.rWarnings.checked = True
|
||||||
|
f.rGreen.selected = True
|
||||||
|
f.iStr1.value = "Hello"
|
||||||
|
|
||||||
|
# Execute the form
|
||||||
|
ok = f.Execute()
|
||||||
|
print("r=%d" % ok)
|
||||||
|
if ok == 1:
|
||||||
|
print("f.str1=%s" % f.iStr1.value)
|
||||||
|
print("f.color1=%x" % f.iColor1.value)
|
||||||
|
print("f.openfile=%s" % f.iFileOpen.value)
|
||||||
|
print("f.savefile=%s" % f.iFileSave.value)
|
||||||
|
print("f.dir=%s" % f.iDir.value)
|
||||||
|
print("f.type=%s" % f.iType.value)
|
||||||
|
print("f.seg=%s" % f.iSegment.value)
|
||||||
|
print("f.rawhex=%x" % f.iRawHex.value)
|
||||||
|
print("f.char=%x" % f.iChar.value)
|
||||||
|
print("f.addr=%x" % f.iAddr.value)
|
||||||
|
print("f.cGroup1=%x" % f.cGroup1.value)
|
||||||
|
print("f.cGroup2=%x" % f.cGroup2.value)
|
||||||
|
|
||||||
|
sel = f.EChooser.GetEmbSelection()
|
||||||
|
if sel is None:
|
||||||
|
print("No selection")
|
||||||
|
else:
|
||||||
|
print("Selection: %s" % sel)
|
||||||
|
# Dispose the form
|
||||||
|
f.Free()
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
def ida_main_legacy():
|
||||||
|
# Here we simply show how to use the old style form format using Python
|
||||||
|
|
||||||
|
# Sample form from kernwin.hpp
|
||||||
|
s = """Sample dialog box
|
||||||
|
|
||||||
|
|
||||||
|
This is sample dialog box for %A
|
||||||
|
using address %$
|
||||||
|
|
||||||
|
<~E~nter value:N:32:16::>
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Use either StringArgument or NumericArgument to pass values to the function
|
||||||
|
num = Form.NumericArgument('N', value=123)
|
||||||
|
ok = idaapi.AskUsingForm(s,
|
||||||
|
Form.StringArgument("PyAskUsingForm").arg,
|
||||||
|
Form.NumericArgument('$', 0x401000).arg,
|
||||||
|
num.arg)
|
||||||
|
if ok == 1:
|
||||||
|
print("You entered: %x" % num.value)
|
||||||
|
|
||||||
|
#</pycode(ex_askusingform)>
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
ida_main()
|
@ -10,38 +10,39 @@ class MyChoose2(Choose2):
|
|||||||
self.icon = 5
|
self.icon = 5
|
||||||
self.selcount = 0
|
self.selcount = 0
|
||||||
self.popup_names = ["Inzert", "Del leet", "Ehdeet", "Ree frech"]
|
self.popup_names = ["Inzert", "Del leet", "Ehdeet", "Ree frech"]
|
||||||
print "created", str(self)
|
print("created %s" % str(self))
|
||||||
|
|
||||||
def OnClose(self):
|
def OnClose(self):
|
||||||
print "closed", str(self)
|
print "closed", str(self)
|
||||||
|
|
||||||
def OnEditLine(self, n):
|
def OnEditLine(self, n):
|
||||||
self.items[n][1] = self.items[n][1] + "*"
|
self.items[n][1] = self.items[n][1] + "*"
|
||||||
print "editing", str(n)
|
print("editing %d" % n)
|
||||||
|
|
||||||
def OnInsertLine(self):
|
def OnInsertLine(self):
|
||||||
self.items.append(self.make_item())
|
self.items.append(self.make_item())
|
||||||
print "insert line"
|
print("insert line")
|
||||||
|
|
||||||
def OnSelectLine(self, n):
|
def OnSelectLine(self, n):
|
||||||
self.selcount += 1
|
self.selcount += 1
|
||||||
Warning("[%02d] selectline '%s'" % (self.selcount, n))
|
Warning("[%02d] selectline '%s'" % (self.selcount, n))
|
||||||
|
|
||||||
def OnGetLine(self, n):
|
def OnGetLine(self, n):
|
||||||
print "getline", str(n)
|
print("getline %d" % n)
|
||||||
return self.items[n]
|
return self.items[n]
|
||||||
|
|
||||||
def OnGetSize(self):
|
def OnGetSize(self):
|
||||||
print "getsize"
|
n = len(self.items)
|
||||||
return len(self.items)
|
print("getsize -> %d" % n)
|
||||||
|
return n
|
||||||
|
|
||||||
def OnDeleteLine(self, n):
|
def OnDeleteLine(self, n):
|
||||||
print "del ",str(n)
|
print("del %d " % n)
|
||||||
del self.items[n]
|
del self.items[n]
|
||||||
return n
|
return n
|
||||||
|
|
||||||
def OnRefresh(self, n):
|
def OnRefresh(self, n):
|
||||||
print "refresh", n
|
print("refresh %d" % n)
|
||||||
return n
|
return n
|
||||||
|
|
||||||
def OnCommand(self, n, cmd_id):
|
def OnCommand(self, n, cmd_id):
|
||||||
@ -73,7 +74,7 @@ class MyChoose2(Choose2):
|
|||||||
return r
|
return r
|
||||||
|
|
||||||
def OnGetLineAttr(self, n):
|
def OnGetLineAttr(self, n):
|
||||||
print "getlineattr", n
|
print("getlineattr %d" % n)
|
||||||
if n == 1:
|
if n == 1:
|
||||||
return [0xFF0000, 0]
|
return [0xFF0000, 0]
|
||||||
|
|
||||||
@ -81,4 +82,3 @@ for i in xrange(1, 5+1):
|
|||||||
c = MyChoose2("choose2 - sample %d" % i, i*2)
|
c = MyChoose2("choose2 - sample %d" % i, i*2)
|
||||||
r = c.show()
|
r = c.show()
|
||||||
print r
|
print r
|
||||||
|
|
@ -1,6 +1,9 @@
|
|||||||
import idautils
|
import idautils
|
||||||
|
|
||||||
s = Strings(False)
|
s = idautils.Strings(False)
|
||||||
s.setup(strtypes=Strings.STR_UNICODE | Strings.STR_C)
|
s.setup(strtypes=Strings.STR_UNICODE | Strings.STR_C)
|
||||||
for i in s:
|
for i, v in enumerate(s):
|
||||||
print "%x: len=%d type=%d -> '%s'" % (i.ea, i.length, i.type, str(i))
|
if v is None:
|
||||||
|
print("Failed to retrieve string index %d" % i)
|
||||||
|
else:
|
||||||
|
print("%x: len=%d type=%d index=%d-> '%s'" % (v.ea, v.length, v.type, i, str(v)))
|
||||||
|
42
examples/ex_uihook.py
Normal file
42
examples/ex_uihook.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#---------------------------------------------------------------------
|
||||||
|
# UI hook example
|
||||||
|
#
|
||||||
|
# (c) Hex-Rays
|
||||||
|
#
|
||||||
|
# Maintained By: IDAPython Team
|
||||||
|
#
|
||||||
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
|
import idaapi
|
||||||
|
|
||||||
|
class MyUiHook(idaapi.UI_Hooks):
|
||||||
|
def __init__(self):
|
||||||
|
idaapi.UI_Hooks.__init__(self)
|
||||||
|
self.cmdname = "<no command>"
|
||||||
|
|
||||||
|
def preprocess(self, name):
|
||||||
|
print("IDA preprocessing command: %s" % name)
|
||||||
|
self.cmdname = name
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def postprocess(self):
|
||||||
|
print("IDA finished processing command: %s" % self.cmdname)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------
|
||||||
|
# Remove an existing hook on second run
|
||||||
|
try:
|
||||||
|
ui_hook_stat = "un"
|
||||||
|
print("UI hook: checking for hook...")
|
||||||
|
uihook
|
||||||
|
print("UI hook: unhooking....")
|
||||||
|
uihook.unhook()
|
||||||
|
del uihook
|
||||||
|
except:
|
||||||
|
print("UI hook: not installed, installing now....")
|
||||||
|
ui_hook_stat = ""
|
||||||
|
uihook = MyUiHook()
|
||||||
|
uihook.hook()
|
||||||
|
|
||||||
|
print("UI hook %sinstalled. Run the script again to %sinstall" % (ui_hook_stat, ui_hook_stat))
|
180
python.cpp
180
python.cpp
@ -49,10 +49,10 @@
|
|||||||
#define IDAPYTHON_DISABLE_EXTLANG 4
|
#define IDAPYTHON_DISABLE_EXTLANG 4
|
||||||
#define PYTHON_DIR_NAME "python"
|
#define PYTHON_DIR_NAME "python"
|
||||||
#define S_IDAPYTHON "IDAPython"
|
#define S_IDAPYTHON "IDAPython"
|
||||||
|
#define S_INIT_PY "init.py"
|
||||||
static const char S_IDC_ARGS_VARNAME[] = "ARGV";
|
static const char S_IDC_ARGS_VARNAME[] = "ARGV";
|
||||||
static const char S_MAIN[] = "__main__";
|
static const char S_MAIN[] = "__main__";
|
||||||
static const char S_IDC_RUNPYTHON_STATEMENT[] = "RunPythonStatement";
|
static const char S_IDC_RUNPYTHON_STATEMENT[] = "RunPythonStatement";
|
||||||
static const char S_HOTKEY_RUNSTATEMENT[] = "Ctrl-F3";
|
|
||||||
static const char S_IDAPYTHON_DATA_NODE[] = "IDAPython_Data";
|
static const char S_IDAPYTHON_DATA_NODE[] = "IDAPython_Data";
|
||||||
|
|
||||||
#ifdef PLUGINFIX
|
#ifdef PLUGINFIX
|
||||||
@ -79,6 +79,7 @@ static bool g_menu_installed = false;
|
|||||||
static int g_run_when = -1;
|
static int g_run_when = -1;
|
||||||
static char g_run_script[QMAXPATH];
|
static char g_run_script[QMAXPATH];
|
||||||
static char g_idapython_dir[QMAXPATH];
|
static char g_idapython_dir[QMAXPATH];
|
||||||
|
static char g_runstmt_hotkey[30] = "Ctrl-F3";
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// Prototypes and forward declarations
|
// Prototypes and forward declarations
|
||||||
@ -124,6 +125,9 @@ static bool box_displayed; // has the wait box been displayed?
|
|||||||
static time_t start_time; // the start time of the execution
|
static time_t start_time; // the start time of the execution
|
||||||
static int script_timeout = 2;
|
static int script_timeout = 2;
|
||||||
static bool g_ui_ready = false;
|
static bool g_ui_ready = false;
|
||||||
|
static bool g_alert_auto_scripts = true;
|
||||||
|
static bool g_remove_cwd_sys_path = false;
|
||||||
|
|
||||||
void end_execution();
|
void end_execution();
|
||||||
void begin_execution();
|
void begin_execution();
|
||||||
|
|
||||||
@ -133,14 +137,15 @@ static int break_check(PyObject *obj, _frame *frame, int what, PyObject *arg)
|
|||||||
{
|
{
|
||||||
if ( wasBreak() )
|
if ( wasBreak() )
|
||||||
{
|
{
|
||||||
/* User pressed Cancel in the waitbox; send KeyboardInterrupt exception */
|
// User pressed Cancel in the waitbox; send KeyboardInterrupt exception
|
||||||
PyErr_SetInterrupt();
|
PyErr_SetInterrupt();
|
||||||
}
|
}
|
||||||
else if ( !box_displayed && ++ninsns > 10 )
|
else if ( !box_displayed && ++ninsns > 10 )
|
||||||
{
|
{
|
||||||
/* We check the timer once every 10 calls */
|
// We check the timer once every 10 calls
|
||||||
ninsns = 0;
|
ninsns = 0;
|
||||||
if ( script_timeout != 0 && (time(NULL) - start_time > script_timeout) ) /* Timeout elapsed? */
|
// Timeout disabled or elapsed?
|
||||||
|
if ( script_timeout != 0 && (time(NULL) - start_time > script_timeout) )
|
||||||
{
|
{
|
||||||
box_displayed = true;
|
box_displayed = true;
|
||||||
show_wait_box("Running Python script");
|
show_wait_box("Running Python script");
|
||||||
@ -323,13 +328,13 @@ static void handle_python_error(char *errbuf, size_t errbufsize)
|
|||||||
static PyObject *GetMainGlobals()
|
static PyObject *GetMainGlobals()
|
||||||
{
|
{
|
||||||
PyObject *module = PyImport_AddModule(S_MAIN);
|
PyObject *module = PyImport_AddModule(S_MAIN);
|
||||||
if ( module == NULL )
|
return module == NULL ? NULL : PyModule_GetDict(module);
|
||||||
return NULL;
|
|
||||||
return PyModule_GetDict(module);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
static void PythonEvalOrExec(const char *str, const char *filename = "<string>")
|
static void PythonEvalOrExec(
|
||||||
|
const char *str,
|
||||||
|
const char *filename = "<string>")
|
||||||
{
|
{
|
||||||
// Compile as an expression
|
// Compile as an expression
|
||||||
PyCompilerFlags cf = {0};
|
PyCompilerFlags cf = {0};
|
||||||
@ -345,11 +350,12 @@ static void PythonEvalOrExec(const char *str, const char *filename = "<string>")
|
|||||||
}
|
}
|
||||||
|
|
||||||
PyObject *py_globals = GetMainGlobals();
|
PyObject *py_globals = GetMainGlobals();
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
PyObject *py_result = PyEval_EvalCode(
|
PyObject *py_result = PyEval_EvalCode(
|
||||||
(PyCodeObject *) py_code,
|
(PyCodeObject *) py_code,
|
||||||
py_globals,
|
py_globals,
|
||||||
py_globals);
|
py_globals);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
Py_DECREF(py_code);
|
Py_DECREF(py_code);
|
||||||
|
|
||||||
if ( py_result == NULL || PyErr_Occurred() )
|
if ( py_result == NULL || PyErr_Occurred() )
|
||||||
@ -379,7 +385,13 @@ static error_t idaapi idc_runpythonstatement(idc_value_t *argv, idc_value_t *res
|
|||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
|
|
||||||
begin_execution();
|
begin_execution();
|
||||||
PyObject *result = PyRun_String(argv[0].c_str(), Py_file_input, globals, globals );
|
PYW_GIL_ENSURE;
|
||||||
|
PyObject *result = PyRun_String(
|
||||||
|
argv[0].c_str(),
|
||||||
|
Py_file_input,
|
||||||
|
globals,
|
||||||
|
globals);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
Py_XDECREF(result);
|
Py_XDECREF(result);
|
||||||
end_execution();
|
end_execution();
|
||||||
|
|
||||||
@ -401,6 +413,45 @@ static error_t idaapi idc_runpythonstatement(idc_value_t *argv, idc_value_t *res
|
|||||||
return eOk;
|
return eOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
const char *idaapi set_python_options(
|
||||||
|
const char *keyword,
|
||||||
|
int value_type,
|
||||||
|
const void *value)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if ( value_type == IDPOPT_STR )
|
||||||
|
{
|
||||||
|
if ( qstrcmp(keyword, "EXEC_STATEMENT_HOTKEY" ) == 0 )
|
||||||
|
{
|
||||||
|
qstrncpy(g_runstmt_hotkey, (const char *)value, sizeof(g_runstmt_hotkey));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( value_type == IDPOPT_NUM )
|
||||||
|
{
|
||||||
|
if ( qstrcmp(keyword, "SCRIPT_TIMEOUT") == 0 )
|
||||||
|
{
|
||||||
|
script_timeout = int(*(uval_t *)value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if ( qstrcmp(keyword, "ALERT_AUTO_SCRIPTS") == 0 )
|
||||||
|
{
|
||||||
|
g_alert_auto_scripts = *(uval_t *)value != 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if ( qstrcmp(keyword, "REMOVE_CWD_SYS_PATH") == 0 )
|
||||||
|
{
|
||||||
|
g_remove_cwd_sys_path = *(uval_t *)value != 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return IDPOPT_BADKEY;
|
||||||
|
} while (false);
|
||||||
|
return IDPOPT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// Check for the presence of a file in IDADIR/python and complain on error
|
// Check for the presence of a file in IDADIR/python and complain on error
|
||||||
bool CheckScriptFiles()
|
bool CheckScriptFiles()
|
||||||
@ -408,7 +459,7 @@ bool CheckScriptFiles()
|
|||||||
static const char *const script_files[] =
|
static const char *const script_files[] =
|
||||||
{
|
{
|
||||||
S_IDC_MODNAME ".py",
|
S_IDC_MODNAME ".py",
|
||||||
"init.py",
|
S_INIT_PY,
|
||||||
"idaapi.py",
|
"idaapi.py",
|
||||||
"idautils.py"
|
"idautils.py"
|
||||||
};
|
};
|
||||||
@ -439,9 +490,19 @@ static int PyRunFile(const char *FileName)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
PyObject *result = PyRun_File(PyFile_AsFile(PyFileObject), FileName, Py_file_input, globals, globals);
|
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
|
PyObject *result = PyRun_File(
|
||||||
|
PyFile_AsFile(PyFileObject),
|
||||||
|
FileName,
|
||||||
|
Py_file_input,
|
||||||
|
globals,
|
||||||
|
globals);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
|
|
||||||
Py_XDECREF(PyFileObject);
|
Py_XDECREF(PyFileObject);
|
||||||
Py_XDECREF(result);
|
Py_XDECREF(result);
|
||||||
|
|
||||||
return result != NULL && !PyErr_Occurred();
|
return result != NULL && !PyErr_Occurred();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,7 +522,7 @@ void IDAPython_RunStatement(void)
|
|||||||
if ( history.getblob(statement, &statement_size, 0, 'A') == NULL )
|
if ( history.getblob(statement, &statement_size, 0, 'A') == NULL )
|
||||||
statement[0] = '\0';
|
statement[0] = '\0';
|
||||||
|
|
||||||
if ( asktext(sizeof(statement), statement, statement, "Enter Python expressions") != NULL )
|
if ( asktext(sizeof(statement), statement, statement, "ACCEPT TABS\nEnter Python expressions") != NULL )
|
||||||
{
|
{
|
||||||
begin_execution();
|
begin_execution();
|
||||||
PyRun_SimpleString(statement);
|
PyRun_SimpleString(statement);
|
||||||
@ -489,7 +550,13 @@ static bool IDAPython_ExecFile(const char *FileName, char *errbuf, size_t errbuf
|
|||||||
strrpl(script, '\\', '//');
|
strrpl(script, '\\', '//');
|
||||||
|
|
||||||
PyObject *py_script = PyString_FromString(script);
|
PyObject *py_script = PyString_FromString(script);
|
||||||
PyObject *py_ret = PyObject_CallFunctionObjArgs(py_execscript, py_script, GetMainGlobals(), NULL);
|
PYW_GIL_ENSURE;
|
||||||
|
PyObject *py_ret = PyObject_CallFunctionObjArgs(
|
||||||
|
py_execscript,
|
||||||
|
py_script,
|
||||||
|
GetMainGlobals(),
|
||||||
|
NULL);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
Py_DECREF(py_script);
|
Py_DECREF(py_script);
|
||||||
Py_DECREF(py_execscript);
|
Py_DECREF(py_execscript);
|
||||||
|
|
||||||
@ -516,7 +583,7 @@ static bool IDAPython_ExecFile(const char *FileName, char *errbuf, size_t errbuf
|
|||||||
}
|
}
|
||||||
// Cannot be otherwise!
|
// Cannot be otherwise!
|
||||||
else
|
else
|
||||||
INTERR();
|
INTERR(30154);
|
||||||
|
|
||||||
Py_XDECREF(py_ret);
|
Py_XDECREF(py_ret);
|
||||||
return ok;
|
return ok;
|
||||||
@ -527,10 +594,12 @@ static bool IDAPython_ExecFile(const char *FileName, char *errbuf, size_t errbuf
|
|||||||
static bool RunScript(const char *script)
|
static bool RunScript(const char *script)
|
||||||
{
|
{
|
||||||
begin_execution();
|
begin_execution();
|
||||||
|
|
||||||
char errbuf[MAXSTR];
|
char errbuf[MAXSTR];
|
||||||
bool ok = IDAPython_ExecFile(script, errbuf, sizeof(errbuf));
|
bool ok = IDAPython_ExecFile(script, errbuf, sizeof(errbuf));
|
||||||
if ( !ok )
|
if ( !ok )
|
||||||
warning("IDAPython: error executing '%s':\n%s", script, errbuf);
|
warning("IDAPython: error executing '%s':\n%s", script, errbuf);
|
||||||
|
|
||||||
end_execution();
|
end_execution();
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
@ -612,7 +681,6 @@ bool idaapi IDAPython_extlang_compile(
|
|||||||
size_t errbufsize)
|
size_t errbufsize)
|
||||||
{
|
{
|
||||||
PyObject *globals = GetMainGlobals();
|
PyObject *globals = GetMainGlobals();
|
||||||
QASSERT(globals != NULL);
|
|
||||||
|
|
||||||
PyCodeObject *code = (PyCodeObject *)Py_CompileString(expr, "<string>", Py_eval_input);
|
PyCodeObject *code = (PyCodeObject *)Py_CompileString(expr, "<string>", Py_eval_input);
|
||||||
if ( code == NULL )
|
if ( code == NULL )
|
||||||
@ -621,11 +689,11 @@ bool idaapi IDAPython_extlang_compile(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the desired function name
|
// Set the desired function name
|
||||||
Py_XDECREF(code->co_name);
|
Py_XDECREF(code->co_name);
|
||||||
code->co_name = PyString_FromString(name);
|
code->co_name = PyString_FromString(name);
|
||||||
|
|
||||||
// create a function out of code
|
// Create a function out of code
|
||||||
PyObject *func = PyFunction_New((PyObject *)code, globals);
|
PyObject *func = PyFunction_New((PyObject *)code, globals);
|
||||||
|
|
||||||
if ( func == NULL )
|
if ( func == NULL )
|
||||||
@ -672,16 +740,18 @@ bool idaapi IDAPython_extlang_run(
|
|||||||
|
|
||||||
if ( imported_module )
|
if ( imported_module )
|
||||||
{
|
{
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
module = PyImport_ImportModule(modname);
|
module = PyImport_ImportModule(modname);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
module = PyImport_AddModule(S_MAIN);
|
module = PyImport_AddModule(S_MAIN);
|
||||||
QASSERT(module != NULL);
|
QASSERT(30156, module != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *globals = PyModule_GetDict(module);
|
PyObject *globals = PyModule_GetDict(module);
|
||||||
QASSERT(globals != NULL);
|
QASSERT(30157, globals != NULL);
|
||||||
|
|
||||||
PyObject *func = PyDict_GetItemString(globals, funcname);
|
PyObject *func = PyDict_GetItemString(globals, funcname);
|
||||||
if ( func == NULL )
|
if ( func == NULL )
|
||||||
@ -692,12 +762,13 @@ bool idaapi IDAPython_extlang_run(
|
|||||||
}
|
}
|
||||||
|
|
||||||
PyCodeObject *code = (PyCodeObject *) PyFunction_GetCode(func);
|
PyCodeObject *code = (PyCodeObject *) PyFunction_GetCode(func);
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
PyObject *pres = PyEval_EvalCodeEx(
|
PyObject *pres = PyEval_EvalCodeEx(
|
||||||
code,
|
code,
|
||||||
globals, NULL,
|
globals, NULL,
|
||||||
&pargs[0], nargs,
|
&pargs[0], nargs,
|
||||||
NULL, 0, NULL, 0, NULL);
|
NULL, 0, NULL, 0, NULL);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
ok = return_python_result(result, pres, errbuf, errbufsize);
|
ok = return_python_result(result, pres, errbuf, errbufsize);
|
||||||
} while ( false );
|
} while ( false );
|
||||||
|
|
||||||
@ -766,7 +837,9 @@ bool idaapi IDAPython_extlang_create_object(
|
|||||||
ok = false;
|
ok = false;
|
||||||
|
|
||||||
// Call the constructor
|
// Call the constructor
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
PyObject *py_res = PyObject_CallObject(py_cls, pargs.empty() ? NULL : pargs[0]);
|
PyObject *py_res = PyObject_CallObject(py_cls, pargs.empty() ? NULL : pargs[0]);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
ok = return_python_result(result, py_res, errbuf, errbufsize);
|
ok = return_python_result(result, py_res, errbuf, errbufsize);
|
||||||
} while ( false );
|
} while ( false );
|
||||||
|
|
||||||
@ -944,7 +1017,9 @@ bool idaapi IDAPython_extlang_calcexpr(
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
begin_execution();
|
begin_execution();
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
PyObject *result = PyRun_String(expr, Py_eval_input, globals, globals);
|
PyObject *result = PyRun_String(expr, Py_eval_input, globals, globals);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
end_execution();
|
end_execution();
|
||||||
|
|
||||||
return return_python_result(rv, result, errbuf, errbufsize);
|
return return_python_result(rv, result, errbuf, errbufsize);
|
||||||
@ -998,7 +1073,9 @@ bool idaapi IDAPython_extlang_call_method(
|
|||||||
if ( !ok )
|
if ( !ok )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
PyObject *py_res = PyObject_CallObject(py_method, pargs.empty() ? NULL : pargs[0]);
|
PyObject *py_res = PyObject_CallObject(py_method, pargs.empty() ? NULL : pargs[0]);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
ok = return_python_result(result, py_res, errbuf, errbufsize);
|
ok = return_python_result(result, py_res, errbuf, errbufsize);
|
||||||
} while ( false );
|
} while ( false );
|
||||||
|
|
||||||
@ -1030,6 +1107,7 @@ extlang_t extlang_python =
|
|||||||
IDAPython_extlang_call_method
|
IDAPython_extlang_call_method
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
void enable_extlang_python(bool enable)
|
void enable_extlang_python(bool enable)
|
||||||
{
|
{
|
||||||
if ( enable )
|
if ( enable )
|
||||||
@ -1042,7 +1120,7 @@ void enable_extlang_python(bool enable)
|
|||||||
// Execute a line in the Python CLI
|
// Execute a line in the Python CLI
|
||||||
bool idaapi IDAPython_cli_execute_line(const char *line)
|
bool idaapi IDAPython_cli_execute_line(const char *line)
|
||||||
{
|
{
|
||||||
// do not process empty lines
|
// Do not process empty lines
|
||||||
if ( line[0] == '\0' )
|
if ( line[0] == '\0' )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -1052,11 +1130,11 @@ bool idaapi IDAPython_cli_execute_line(const char *line)
|
|||||||
else
|
else
|
||||||
last_line += 1;
|
last_line += 1;
|
||||||
|
|
||||||
// skip empty lines
|
// Skip empty lines
|
||||||
if ( last_line[0] != '\0' )
|
if ( last_line[0] != '\0' )
|
||||||
{
|
{
|
||||||
// line ends with ":" or begins with a space character?
|
// Line ends with ":" or begins with a space character?
|
||||||
bool more = last_line[qstrlen(last_line)-1] == ':' || isspace(last_line[0]);
|
bool more = last_line[qstrlen(last_line)-1] == ':' || qisspace(last_line[0]);
|
||||||
if ( more )
|
if ( more )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1080,7 +1158,9 @@ bool idaapi IDAPYthon_cli_complete_line(
|
|||||||
if ( py_complete == NULL )
|
if ( py_complete == NULL )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
PyObject *py_ret = PyObject_CallFunction(py_complete, "sisi", prefix, n, line, x);
|
PyObject *py_ret = PyObject_CallFunction(py_complete, "sisi", prefix, n, line, x);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
|
|
||||||
Py_DECREF(py_complete);
|
Py_DECREF(py_complete);
|
||||||
|
|
||||||
@ -1124,7 +1204,9 @@ void enable_python_cli(bool enable)
|
|||||||
// Prints the IDAPython copyright banner
|
// Prints the IDAPython copyright banner
|
||||||
void py_print_banner()
|
void py_print_banner()
|
||||||
{
|
{
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
PyRun_SimpleString("print_banner()");
|
PyRun_SimpleString("print_banner()");
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
@ -1136,8 +1218,11 @@ static void install_python_menus()
|
|||||||
|
|
||||||
// Add menu items for all the functions
|
// Add menu items for all the functions
|
||||||
// Note: Different paths are used for the GUI version
|
// Note: Different paths are used for the GUI version
|
||||||
add_menu_item("File/IDC command...", "P~y~thon command...",
|
add_menu_item(
|
||||||
S_HOTKEY_RUNSTATEMENT, SETMENU_APP,
|
"File/IDC command...",
|
||||||
|
"P~y~thon command...",
|
||||||
|
g_runstmt_hotkey,
|
||||||
|
SETMENU_APP,
|
||||||
IDAPython_Menu_Callback,
|
IDAPython_Menu_Callback,
|
||||||
(void *)IDAPYTHON_RUNSTATEMENT);
|
(void *)IDAPYTHON_RUNSTATEMENT);
|
||||||
|
|
||||||
@ -1277,6 +1362,19 @@ bool IDAPython_Init(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Read configuration value
|
||||||
|
read_user_config_file("python.cfg", set_python_options, NULL);
|
||||||
|
if ( g_alert_auto_scripts )
|
||||||
|
{
|
||||||
|
const char *autofn = pywraps_check_autoscripts();
|
||||||
|
if ( autofn != NULL
|
||||||
|
&& askyn_c(0, "HIDECANCEL\nTITLE IDAPython\nThe script '%s' was found in the current directory and will be automatically executed by Python.\n\n"
|
||||||
|
"Do you want to continue loading IDAPython?", autofn) == 0 )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Start the interpreter
|
// Start the interpreter
|
||||||
Py_Initialize();
|
Py_Initialize();
|
||||||
if ( !Py_IsInitialized() )
|
if ( !Py_IsInitialized() )
|
||||||
@ -1285,16 +1383,22 @@ bool IDAPython_Init(void)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enable multi-threading support
|
||||||
|
if ( !PyEval_ThreadsInitialized() )
|
||||||
|
PyEval_InitThreads();
|
||||||
|
|
||||||
// Init the SWIG wrapper
|
// Init the SWIG wrapper
|
||||||
init_idaapi();
|
init_idaapi();
|
||||||
|
|
||||||
// Set IDAPYTHON_VERSION in Python
|
// Set IDAPYTHON_VERSION in Python
|
||||||
qsnprintf(tmp, sizeof(tmp), "IDAPYTHON_VERSION=(%d, %d, %d, '%s', %d)", \
|
qsnprintf(tmp, sizeof(tmp), "IDAPYTHON_VERSION=(%d, %d, %d, '%s', %d)\n"
|
||||||
|
"IDAPYTHON_REMOVE_CWD_SYS_PATH = %s\n",
|
||||||
VER_MAJOR,
|
VER_MAJOR,
|
||||||
VER_MINOR,
|
VER_MINOR,
|
||||||
VER_PATCH,
|
VER_PATCH,
|
||||||
VER_STATUS,
|
VER_STATUS,
|
||||||
VER_SERIAL);
|
VER_SERIAL,
|
||||||
|
g_remove_cwd_sys_path ? "True" : "False");
|
||||||
PyRun_SimpleString(tmp);
|
PyRun_SimpleString(tmp);
|
||||||
|
|
||||||
// Install extlang. Needs to be done before running init.py
|
// Install extlang. Needs to be done before running init.py
|
||||||
@ -1302,11 +1406,11 @@ bool IDAPython_Init(void)
|
|||||||
install_extlang(&extlang_python);
|
install_extlang(&extlang_python);
|
||||||
|
|
||||||
// Execute init.py (for Python side initialization)
|
// Execute init.py (for Python side initialization)
|
||||||
qmakepath(tmp, MAXSTR, g_idapython_dir, "init.py", NULL);
|
qmakepath(tmp, MAXSTR, g_idapython_dir, S_INIT_PY, NULL);
|
||||||
if ( !PyRunFile(tmp) )
|
if ( !PyRunFile(tmp) )
|
||||||
{
|
{
|
||||||
handle_python_error(tmp, sizeof(tmp));
|
handle_python_error(tmp, sizeof(tmp));
|
||||||
warning("IDAPython: error executing init.py:\n%s", tmp);
|
warning("IDAPython: error executing " S_INIT_PY ":\n%s", tmp);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1357,18 +1461,18 @@ void IDAPython_Term(void)
|
|||||||
del_menu_item("File/Python command...");
|
del_menu_item("File/Python command...");
|
||||||
g_menu_installed = false;
|
g_menu_installed = false;
|
||||||
|
|
||||||
// Remove the CLI
|
|
||||||
enable_python_cli(false);
|
|
||||||
|
|
||||||
// Remove the extlang
|
|
||||||
remove_extlang(&extlang_python);
|
|
||||||
|
|
||||||
// Notify about IDA closing
|
// Notify about IDA closing
|
||||||
pywraps_nw_notify(NW_TERMIDA_SLOT);
|
pywraps_nw_notify(NW_TERMIDA_SLOT);
|
||||||
|
|
||||||
// De-init notify_when
|
// De-init notify_when
|
||||||
pywraps_nw_term();
|
pywraps_nw_term();
|
||||||
|
|
||||||
|
// Remove the CLI
|
||||||
|
enable_python_cli(false);
|
||||||
|
|
||||||
|
// Remove the extlang
|
||||||
|
remove_extlang(&extlang_python);
|
||||||
|
|
||||||
// De-init pywraps
|
// De-init pywraps
|
||||||
deinit_pywraps();
|
deinit_pywraps();
|
||||||
|
|
||||||
@ -1446,5 +1550,5 @@ plugin_t PLUGIN =
|
|||||||
// the preferred short name of the plugin
|
// the preferred short name of the plugin
|
||||||
S_IDAPYTHON,
|
S_IDAPYTHON,
|
||||||
// the preferred hotkey to run the plugin
|
// the preferred hotkey to run the plugin
|
||||||
S_HOTKEY_RUNSTATEMENT
|
NULL
|
||||||
};
|
};
|
||||||
|
@ -310,6 +310,37 @@ def FuncItems(start):
|
|||||||
ok = fii.next_code()
|
ok = fii.next_code()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def DecodePrecedingInstruction(ea):
|
||||||
|
"""
|
||||||
|
Decode preceding instruction in the execution flow.
|
||||||
|
|
||||||
|
@param ea: address to decode
|
||||||
|
@return: (None or the decode instruction, farref)
|
||||||
|
farref will contain 'true' if followed an xref, false otherwise
|
||||||
|
"""
|
||||||
|
prev_addr, farref = idaapi.decode_preceding_insn(ea)
|
||||||
|
if prev_addr == idaapi.BADADDR:
|
||||||
|
return (None, False)
|
||||||
|
else:
|
||||||
|
return (idaapi.cmd.copy(), farref)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def DecodePreviousInstruction(ea):
|
||||||
|
"""
|
||||||
|
Decodes the previous instruction and returns an insn_t like class
|
||||||
|
|
||||||
|
@param ea: address to decode
|
||||||
|
@return: None or a new insn_t instance
|
||||||
|
"""
|
||||||
|
inslen = idaapi.decode_prev_insn(ea)
|
||||||
|
if inslen == 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return idaapi.cmd.copy()
|
||||||
|
|
||||||
|
|
||||||
def DecodeInstruction(ea):
|
def DecodeInstruction(ea):
|
||||||
"""
|
"""
|
||||||
Decodes an instruction and returns an insn_t like class
|
Decodes an instruction and returns an insn_t like class
|
||||||
@ -434,6 +465,7 @@ class Strings(object):
|
|||||||
"""Clears the strings list cache"""
|
"""Clears the strings list cache"""
|
||||||
self.refresh(0, 0) # when ea1=ea2 the kernel will clear the cache
|
self.refresh(0, 0) # when ea1=ea2 the kernel will clear the cache
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, default_setup = True):
|
def __init__(self, default_setup = True):
|
||||||
"""
|
"""
|
||||||
Initializes the Strings enumeration helper class
|
Initializes the Strings enumeration helper class
|
||||||
@ -446,6 +478,7 @@ class Strings(object):
|
|||||||
|
|
||||||
self._si = idaapi.string_info_t()
|
self._si = idaapi.string_info_t()
|
||||||
|
|
||||||
|
|
||||||
def refresh(self, ea1=None, ea2=None):
|
def refresh(self, ea1=None, ea2=None):
|
||||||
"""Refreshes the strings list"""
|
"""Refreshes the strings list"""
|
||||||
if ea1 is None:
|
if ea1 is None:
|
||||||
@ -456,6 +489,7 @@ class Strings(object):
|
|||||||
idaapi.refresh_strlist(ea1, ea2)
|
idaapi.refresh_strlist(ea1, ea2)
|
||||||
self.size = idaapi.get_strlist_qty()
|
self.size = idaapi.get_strlist_qty()
|
||||||
|
|
||||||
|
|
||||||
def setup(self,
|
def setup(self,
|
||||||
strtypes = STR_C,
|
strtypes = STR_C,
|
||||||
minlen = 5,
|
minlen = 5,
|
||||||
@ -483,15 +517,24 @@ class Strings(object):
|
|||||||
# Automatically refreshes
|
# Automatically refreshes
|
||||||
self.refresh()
|
self.refresh()
|
||||||
|
|
||||||
|
|
||||||
|
def _get_item(self, index):
|
||||||
|
if not idaapi.get_strlist_item(index, self._si):
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return Strings.StringItem(self._si)
|
||||||
|
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return (self._get_item(index) for index in xrange(0, self.size))
|
||||||
|
|
||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, index):
|
||||||
"""Returns a string item or None"""
|
"""Returns a string item or None"""
|
||||||
if index >= self.size:
|
if index >= self.size:
|
||||||
raise StopIteration
|
raise KeyError
|
||||||
|
else:
|
||||||
if idaapi.get_strlist_item(index, self._si):
|
return self._get_item(index)
|
||||||
return Strings.StringItem(self._si)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
def GetIdbDir():
|
def GetIdbDir():
|
||||||
@ -646,6 +689,12 @@ class peutils_t(object):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "peutils_t(imagebase=%s, header=%s)" % (hex(self.imagebase), hex(self.header))
|
return "peutils_t(imagebase=%s, header=%s)" % (hex(self.imagebase), hex(self.header))
|
||||||
|
|
||||||
|
def header(self):
|
||||||
|
"""
|
||||||
|
Returns the complete PE header as an instance of peheader_t (defined in the SDK).
|
||||||
|
"""
|
||||||
|
return self.__penode.valobj()
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
cpu = _cpu()
|
cpu = _cpu()
|
||||||
"""This is a special class instance used to access the registers as if they were attributes of this object.
|
"""This is a special class instance used to access the registers as if they were attributes of this object.
|
||||||
|
@ -702,7 +702,7 @@ def MakeStr(ea, endea):
|
|||||||
|
|
||||||
@note: The type of an existing string is returned by GetStringType()
|
@note: The type of an existing string is returned by GetStringType()
|
||||||
"""
|
"""
|
||||||
return idaapi.make_ascii_string(ea, endea - ea, GetLongPrm(INF_STRTYPE))
|
return idaapi.make_ascii_string(ea, 0 if endea == BADADDR else endea - ea, GetLongPrm(INF_STRTYPE))
|
||||||
|
|
||||||
|
|
||||||
def MakeData(ea, flags, size, tid):
|
def MakeData(ea, flags, size, tid):
|
||||||
@ -1710,7 +1710,7 @@ def Byte(ea):
|
|||||||
might have more 1's.
|
might have more 1's.
|
||||||
To check if a byte has a value, use functions hasValue(GetFlags(ea))
|
To check if a byte has a value, use functions hasValue(GetFlags(ea))
|
||||||
"""
|
"""
|
||||||
return idaapi.get_byte(ea)
|
return idaapi.get_full_byte(ea)
|
||||||
|
|
||||||
|
|
||||||
def __DbgValue(ea, len):
|
def __DbgValue(ea, len):
|
||||||
@ -1781,7 +1781,7 @@ def Word(ea):
|
|||||||
If the current byte size is different from 8 bits, then the returned value
|
If the current byte size is different from 8 bits, then the returned value
|
||||||
might have more 1's.
|
might have more 1's.
|
||||||
"""
|
"""
|
||||||
return idaapi.get_word(ea)
|
return idaapi.get_full_word(ea)
|
||||||
|
|
||||||
|
|
||||||
def Dword(ea):
|
def Dword(ea):
|
||||||
@ -1792,7 +1792,7 @@ def Dword(ea):
|
|||||||
|
|
||||||
@return: the value of the double word. If failed returns -1
|
@return: the value of the double word. If failed returns -1
|
||||||
"""
|
"""
|
||||||
return idaapi.get_long(ea)
|
return idaapi.get_full_long(ea)
|
||||||
|
|
||||||
|
|
||||||
def Qword(ea):
|
def Qword(ea):
|
||||||
@ -1802,10 +1802,8 @@ def Qword(ea):
|
|||||||
@param ea: linear address
|
@param ea: linear address
|
||||||
|
|
||||||
@return: the value of the quadro word. If failed, returns -1
|
@return: the value of the quadro word. If failed, returns -1
|
||||||
|
|
||||||
@note: this function is available only in the 64-bit version of IDA Pro
|
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError, "will be implemented in the 64-bit version"
|
return idaapi.get_qword(ea)
|
||||||
|
|
||||||
|
|
||||||
def GetFloat(ea):
|
def GetFloat(ea):
|
||||||
@ -1839,7 +1837,7 @@ def LocByName(name):
|
|||||||
@param name: name of program byte
|
@param name: name of program byte
|
||||||
|
|
||||||
@return: address of the name
|
@return: address of the name
|
||||||
badaddr - no such name
|
BADADDR - No such name
|
||||||
"""
|
"""
|
||||||
return idaapi.get_name_ea(BADADDR, name)
|
return idaapi.get_name_ea(BADADDR, name)
|
||||||
|
|
||||||
@ -1964,7 +1962,7 @@ def PrevAddr(ea):
|
|||||||
return idaapi.prevaddr(ea)
|
return idaapi.prevaddr(ea)
|
||||||
|
|
||||||
|
|
||||||
def NextHead(ea, maxea):
|
def NextHead(ea, maxea=BADADDR):
|
||||||
"""
|
"""
|
||||||
Get next defined item (instruction or data) in the program
|
Get next defined item (instruction or data) in the program
|
||||||
|
|
||||||
@ -1977,7 +1975,7 @@ def NextHead(ea, maxea):
|
|||||||
return idaapi.next_head(ea, maxea)
|
return idaapi.next_head(ea, maxea)
|
||||||
|
|
||||||
|
|
||||||
def PrevHead(ea, minea):
|
def PrevHead(ea, minea=0):
|
||||||
"""
|
"""
|
||||||
Get previous defined item (instruction or data) in the program
|
Get previous defined item (instruction or data) in the program
|
||||||
|
|
||||||
@ -2938,6 +2936,17 @@ def AskLong(defval, prompt):
|
|||||||
return idaapi.asklong(defval, prompt)
|
return idaapi.asklong(defval, prompt)
|
||||||
|
|
||||||
|
|
||||||
|
def ProcessUiAction(name, flags=0):
|
||||||
|
"""
|
||||||
|
Invokes an IDA Pro UI action by name
|
||||||
|
|
||||||
|
@param name: Command name
|
||||||
|
@param flags: Reserved. Must be zero
|
||||||
|
@return: Boolean
|
||||||
|
"""
|
||||||
|
return idaapi.process_ui_action(name, flags)
|
||||||
|
|
||||||
|
|
||||||
def AskSeg(defval, prompt):
|
def AskSeg(defval, prompt):
|
||||||
"""
|
"""
|
||||||
Ask the user to enter a segment value
|
Ask the user to enter a segment value
|
||||||
@ -3374,7 +3383,7 @@ def SegByName(segname):
|
|||||||
if not seg:
|
if not seg:
|
||||||
return BADADDR
|
return BADADDR
|
||||||
|
|
||||||
return seg.startEA
|
return seg.sel
|
||||||
|
|
||||||
|
|
||||||
def SetSegDefReg(ea, reg, value):
|
def SetSegDefReg(ea, reg, value):
|
||||||
@ -6258,14 +6267,14 @@ def ParseType(inputtype, flags):
|
|||||||
"""
|
"""
|
||||||
return idaapi.idc_parse_decl(idaapi.cvar.idati, inputtype, flags)
|
return idaapi.idc_parse_decl(idaapi.cvar.idati, inputtype, flags)
|
||||||
|
|
||||||
def ParseTypes(inputtype, flags):
|
def ParseTypes(inputtype, flags = 0):
|
||||||
"""
|
"""
|
||||||
Parse type declarations
|
Parse type declarations
|
||||||
|
|
||||||
@param inputtype: file name or C declarations (depending on the flags)
|
@param inputtype: file name or C declarations (depending on the flags)
|
||||||
@param flags: combination of PT_... constants or 0
|
@param flags: combination of PT_... constants or 0
|
||||||
|
|
||||||
@return: number of errors
|
@return: number of parsing errors (0 no errors)
|
||||||
"""
|
"""
|
||||||
return idaapi.idc_parse_types(inputtype, flags)
|
return idaapi.idc_parse_types(inputtype, flags)
|
||||||
|
|
||||||
@ -6790,7 +6799,6 @@ def GetProcessState():
|
|||||||
"""
|
"""
|
||||||
return idaapi.get_process_state()
|
return idaapi.get_process_state()
|
||||||
|
|
||||||
DSTATE_SUSP_FOR_EVENT = -2 # process is currently suspended to react to a debug event (not used)
|
|
||||||
DSTATE_SUSP = -1 # process is suspended
|
DSTATE_SUSP = -1 # process is suspended
|
||||||
DSTATE_NOTASK = 0 # no process is currently debugged
|
DSTATE_NOTASK = 0 # no process is currently debugged
|
||||||
DSTATE_RUN = 1 # process is running
|
DSTATE_RUN = 1 # process is running
|
||||||
@ -7109,7 +7117,7 @@ def GetRegValue(name):
|
|||||||
"""
|
"""
|
||||||
rv = idaapi.regval_t()
|
rv = idaapi.regval_t()
|
||||||
res = idaapi.get_reg_val(name, rv)
|
res = idaapi.get_reg_val(name, rv)
|
||||||
assert res, "get_reg_val() failed, bogus name perhaps?"
|
assert res, "get_reg_val() failed, bogus register name ('%s') perhaps?" % name
|
||||||
return rv.ival
|
return rv.ival
|
||||||
|
|
||||||
|
|
||||||
@ -7209,11 +7217,25 @@ BPTATTR_COUNT = 4
|
|||||||
BPTATTR_FLAGS = 5
|
BPTATTR_FLAGS = 5
|
||||||
BPT_BRK = 0x01 # the debugger stops on this breakpoint
|
BPT_BRK = 0x01 # the debugger stops on this breakpoint
|
||||||
BPT_TRACE = 0x02 # the debugger adds trace information when this breakpoint is reached
|
BPT_TRACE = 0x02 # the debugger adds trace information when this breakpoint is reached
|
||||||
BPT_UPDMEM = 0x04 # update memory contents before evaluating bpt condition
|
BPT_UPDMEM = 0x04 # refresh the memory layout and contents before evaluating bpt condition
|
||||||
BPT_UPDSEG = 0x08 # update memory config before evaluating bpt condition
|
BPT_ENABLED = 0x08 # enabled?
|
||||||
|
BPT_LOWCND = 0x10 # condition is calculated at low level (on the server side)
|
||||||
|
|
||||||
BPTATTR_COND = 6 # Breakpoint condition. NOTE: the return value is a string in this case
|
BPTATTR_COND = 6 # Breakpoint condition. NOTE: the return value is a string in this case
|
||||||
|
|
||||||
|
# Breakpoint location type:
|
||||||
|
BPLT_ABS = 0 # Absolute address. Attributes:
|
||||||
|
# - locinfo: absolute address
|
||||||
|
|
||||||
|
BPLT_REL = 1 # Module relative address. Attributes:
|
||||||
|
# - locpath: the module path
|
||||||
|
# - locinfo: offset from the module base address
|
||||||
|
|
||||||
|
BPLT_SYM = 2 # Symbolic name. The name will be resolved on DLL load/unload
|
||||||
|
# events and on naming an address. Attributes:
|
||||||
|
# - locpath: symbol name
|
||||||
|
# - locinfo: offset from the symbol base address
|
||||||
|
|
||||||
|
|
||||||
def SetBptAttr(address, bptattr, value):
|
def SetBptAttr(address, bptattr, value):
|
||||||
"""
|
"""
|
||||||
@ -7530,16 +7552,44 @@ def WriteTxt(filepath, ea1, ea2):
|
|||||||
def WriteExe(filepath):
|
def WriteExe(filepath):
|
||||||
return GenerateFile(OFILE_EXE, filepath, 0, BADADDR, 0)
|
return GenerateFile(OFILE_EXE, filepath, 0, BADADDR, 0)
|
||||||
|
|
||||||
def AddConst(enum_id,name,value): return AddConstEx(enum_id,name,value, idaapi.BADADDR)
|
|
||||||
def AddStruc(index,name): return AddStrucEx(index,name,0)
|
UTP_STRUCT = idaapi.UTP_STRUCT
|
||||||
def AddUnion(index,name): return AddStrucEx(index,name,1)
|
UTP_ENUM = idaapi.UTP_ENUM
|
||||||
def OpStroff(ea,n,strid): return OpStroffEx(ea,n,strid,0)
|
|
||||||
def OpEnum(ea,n,enumid): return OpEnumEx(ea,n,enumid,0)
|
|
||||||
|
def BeginTypeUpdating(utp):
|
||||||
|
"""
|
||||||
|
Begin type updating. Use this function if you
|
||||||
|
plan to call AddEnumConst or similar type modification functions
|
||||||
|
many times or from inside a loop
|
||||||
|
|
||||||
|
@param utp: one of UTP_xxxx consts
|
||||||
|
@return: None
|
||||||
|
"""
|
||||||
|
return idaapi.begin_type_updating(utp)
|
||||||
|
|
||||||
|
|
||||||
|
def EndTypeUpdating(utp):
|
||||||
|
"""
|
||||||
|
End type updating. Refreshes the type system
|
||||||
|
at the end of type modification operations
|
||||||
|
|
||||||
|
@param utp: one of idaapi.UTP_xxxx consts
|
||||||
|
@return: None
|
||||||
|
"""
|
||||||
|
return idaapi.end_type_updating(utp)
|
||||||
|
|
||||||
|
|
||||||
|
def AddConst(enum_id, name,value): return AddConstEx(enum_id, name, value, idaapi.BADADDR)
|
||||||
|
def AddStruc(index, name): return AddStrucEx(index,name, 0)
|
||||||
|
def AddUnion(index, name): return AddStrucEx(index,name, 1)
|
||||||
|
def OpStroff(ea, n, strid): return OpStroffEx(ea,n,strid, 0)
|
||||||
|
def OpEnum(ea, n, enumid): return OpEnumEx(ea,n,enumid, 0)
|
||||||
def DelConst(constid, v, mask): return DelConstEx(constid, v, 0, mask)
|
def DelConst(constid, v, mask): return DelConstEx(constid, v, 0, mask)
|
||||||
def GetConst(constid, v, mask): return GetConstEx(constid, v, 0, mask)
|
def GetConst(constid, v, mask): return GetConstEx(constid, v, 0, mask)
|
||||||
def AnalyseArea(sEA, eEA): return AnalyzeArea(sEA,eEA)
|
def AnalyseArea(sEA, eEA): return AnalyzeArea(sEA,eEA)
|
||||||
|
|
||||||
def MakeStruct(ea,name): return MakeStructEx(ea, -1, name)
|
def MakeStruct(ea, name): return MakeStructEx(ea, -1, name)
|
||||||
def Name(ea): return NameEx(BADADDR, ea)
|
def Name(ea): return NameEx(BADADDR, ea)
|
||||||
def GetTrueName(ea): return GetTrueNameEx(BADADDR, ea)
|
def GetTrueName(ea): return GetTrueNameEx(BADADDR, ea)
|
||||||
def MakeName(ea, name): return MakeNameEx(ea,name,SN_CHECK)
|
def MakeName(ea, name): return MakeNameEx(ea,name,SN_CHECK)
|
||||||
|
@ -31,7 +31,7 @@ class IDAPythonStdOut:
|
|||||||
# Swap out the unprintable characters
|
# Swap out the unprintable characters
|
||||||
text = text.decode('ascii', 'replace').encode('ascii', 'replace')
|
text = text.decode('ascii', 'replace').encode('ascii', 'replace')
|
||||||
# Print to IDA message window
|
# Print to IDA message window
|
||||||
_idaapi.msg(text.replace("%", "%%"))
|
_idaapi.msg(text)
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
pass
|
pass
|
||||||
@ -61,9 +61,9 @@ def print_banner():
|
|||||||
]
|
]
|
||||||
sepline = '-' * (max([len(s) for s in banner])+1)
|
sepline = '-' * (max([len(s) for s in banner])+1)
|
||||||
|
|
||||||
print sepline
|
print(sepline)
|
||||||
print "\n".join(banner)
|
print("\n".join(banner))
|
||||||
print sepline
|
print(sepline)
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
@ -76,8 +76,19 @@ sys.argv = [""]
|
|||||||
# Have to make sure Python finds our modules
|
# Have to make sure Python finds our modules
|
||||||
sys.path.append(_idaapi.idadir("python"))
|
sys.path.append(_idaapi.idadir("python"))
|
||||||
|
|
||||||
|
# Remove current directory from the top of the patch search
|
||||||
|
if '' in sys.path: # On non Windows, the empty path is added
|
||||||
|
sys.path.remove('')
|
||||||
|
|
||||||
|
if os.getcwd() in sys.path:
|
||||||
|
sys.path.remove(os.getcwd())
|
||||||
|
|
||||||
|
# ...and add it to the end if needed
|
||||||
|
if not IDAPYTHON_REMOVE_CWD_SYS_PATH:
|
||||||
|
sys.path.append(os.getcwd())
|
||||||
|
|
||||||
# Import all the required modules
|
# Import all the required modules
|
||||||
from idaapi import Choose, get_user_idadir, cvar, Choose2, Appcall
|
from idaapi import Choose, get_user_idadir, cvar, Choose2, Appcall, Form
|
||||||
from idc import *
|
from idc import *
|
||||||
from idautils import *
|
from idautils import *
|
||||||
import idaapi
|
import idaapi
|
||||||
|
37
pywraps.hpp
37
pywraps.hpp
@ -5,6 +5,7 @@
|
|||||||
// Types
|
// Types
|
||||||
#ifndef PYUL_DEFINED
|
#ifndef PYUL_DEFINED
|
||||||
#define PYUL_DEFINED
|
#define PYUL_DEFINED
|
||||||
|
typedef unsigned PY_LONG_LONG PY_ULONG_LONG;
|
||||||
#ifdef __EA64__
|
#ifdef __EA64__
|
||||||
typedef unsigned PY_LONG_LONG pyul_t;
|
typedef unsigned PY_LONG_LONG pyul_t;
|
||||||
typedef PY_LONG_LONG pyl_t;
|
typedef PY_LONG_LONG pyl_t;
|
||||||
@ -56,6 +57,31 @@ typedef qvector<PyObject *> ppyobject_vec_t;
|
|||||||
#define CIP_OK 1 // Success
|
#define CIP_OK 1 // Success
|
||||||
#define CIP_OK_NODECREF 2 // Success but do not decrement its reference
|
#define CIP_OK_NODECREF 2 // Success but do not decrement its reference
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
class CGilStateAuto
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
PyGILState_STATE state;
|
||||||
|
public:
|
||||||
|
CGilStateAuto()
|
||||||
|
{
|
||||||
|
state = PyGILState_Ensure();
|
||||||
|
}
|
||||||
|
|
||||||
|
~CGilStateAuto()
|
||||||
|
{
|
||||||
|
PyGILState_Release(state);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Declare a variable to acquire/release the GIL
|
||||||
|
#define PYW_GIL_AUTO_ENSURE CGilStateAuto GIL_STATE_AUTO
|
||||||
|
|
||||||
|
// Macros to acquire/release GIL in a given scope
|
||||||
|
#define PYW_GIL_ENSURE_N(name) PyGILState_STATE gil_state##name = PyGILState_Ensure()
|
||||||
|
#define PYW_GIL_RELEASE_N(name) PyGILState_Release(gil_state##name)
|
||||||
|
|
||||||
|
#define PYW_GIL_ENSURE PYW_GIL_ENSURE_N(_)
|
||||||
|
#define PYW_GIL_RELEASE PYW_GIL_RELEASE_N(_)
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// All the exported functions from PyWraps are forward declared here
|
// All the exported functions from PyWraps are forward declared here
|
||||||
insn_t *insn_t_get_clink(PyObject *self);
|
insn_t *insn_t_get_clink(PyObject *self);
|
||||||
@ -86,7 +112,8 @@ bool PyW_IsSequenceType(PyObject *obj);
|
|||||||
bool PyW_GetError(qstring *out = NULL);
|
bool PyW_GetError(qstring *out = NULL);
|
||||||
|
|
||||||
// If an error occured (it calls PyGetError) it displays it and return TRUE
|
// If an error occured (it calls PyGetError) it displays it and return TRUE
|
||||||
bool PyW_ShowErr(const char *cb_name);
|
// This function is used when calling callbacks
|
||||||
|
bool PyW_ShowCbErr(const char *cb_name);
|
||||||
|
|
||||||
// Utility function to create a class instance whose constructor takes zero arguments
|
// Utility function to create a class instance whose constructor takes zero arguments
|
||||||
PyObject *create_idaapi_class_instance0(const char *clsname);
|
PyObject *create_idaapi_class_instance0(const char *clsname);
|
||||||
@ -124,6 +151,12 @@ Py_ssize_t pyvar_walk_list(
|
|||||||
int (idaapi *cb)(PyObject *py_item, Py_ssize_t index, void *ud) = NULL,
|
int (idaapi *cb)(PyObject *py_item, Py_ssize_t index, void *ud) = NULL,
|
||||||
void *ud = NULL);
|
void *ud = NULL);
|
||||||
|
|
||||||
|
// Converts an intvec_t to a Python list object
|
||||||
|
PyObject *PyW_IntVecToPyList(const intvec_t &intvec);
|
||||||
|
|
||||||
|
// Converts an Python list to an intvec
|
||||||
|
void PyW_PyListToIntVec(PyObject *py_list, intvec_t &intvec);
|
||||||
|
|
||||||
// Returns a reference to a class
|
// Returns a reference to a class
|
||||||
PyObject *get_idaapi_attr(const char *attr);
|
PyObject *get_idaapi_attr(const char *attr);
|
||||||
|
|
||||||
@ -132,4 +165,6 @@ bool pywraps_nw_term();
|
|||||||
bool pywraps_nw_notify(int slot, ...);
|
bool pywraps_nw_notify(int slot, ...);
|
||||||
bool pywraps_nw_init();
|
bool pywraps_nw_init();
|
||||||
|
|
||||||
|
const char *pywraps_check_autoscripts();
|
||||||
|
|
||||||
#endif
|
#endif
|
63
swig/bytes.i
63
swig/bytes.i
@ -101,7 +101,9 @@
|
|||||||
static bool idaapi py_testf_cb(flags_t flags, void *ud)
|
static bool idaapi py_testf_cb(flags_t flags, void *ud)
|
||||||
{
|
{
|
||||||
PyObject *py_flags = PyLong_FromUnsignedLong(flags);
|
PyObject *py_flags = PyLong_FromUnsignedLong(flags);
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
PyObject *result = PyObject_CallFunctionObjArgs((PyObject *) ud, py_flags, NULL);
|
PyObject *result = PyObject_CallFunctionObjArgs((PyObject *) ud, py_flags, NULL);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
bool ret = result != NULL && PyObject_IsTrue(result);
|
bool ret = result != NULL && PyObject_IsTrue(result);
|
||||||
Py_XDECREF(result);
|
Py_XDECREF(result);
|
||||||
Py_XDECREF(py_flags);
|
Py_XDECREF(py_flags);
|
||||||
@ -114,6 +116,7 @@ static ea_t py_npthat(ea_t ea, ea_t bound, PyObject *py_callable, bool next)
|
|||||||
{
|
{
|
||||||
if ( !PyCallable_Check(py_callable) )
|
if ( !PyCallable_Check(py_callable) )
|
||||||
return BADADDR;
|
return BADADDR;
|
||||||
|
else
|
||||||
return (next ? nextthat : prevthat)(ea, bound, py_testf_cb, py_callable);
|
return (next ? nextthat : prevthat)(ea, bound, py_testf_cb, py_callable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,8 +137,17 @@ class py_custom_data_type_t
|
|||||||
size_t nbytes) // size of the future item
|
size_t nbytes) // size of the future item
|
||||||
{
|
{
|
||||||
py_custom_data_type_t *_this = (py_custom_data_type_t *)ud;
|
py_custom_data_type_t *_this = (py_custom_data_type_t *)ud;
|
||||||
PyObject *py_result = PyObject_CallMethod(_this->py_self, (char *)S_MAY_CREATE_AT, PY_FMT64 PY_FMT64, pyul_t(ea), pyul_t(nbytes));
|
|
||||||
PyW_ShowErr(S_MAY_CREATE_AT);
|
PYW_GIL_ENSURE;
|
||||||
|
PyObject *py_result = PyObject_CallMethod(
|
||||||
|
_this->py_self,
|
||||||
|
(char *)S_MAY_CREATE_AT,
|
||||||
|
PY_FMT64 PY_FMT64,
|
||||||
|
pyul_t(ea),
|
||||||
|
pyul_t(nbytes));
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
|
|
||||||
|
PyW_ShowCbErr(S_MAY_CREATE_AT);
|
||||||
bool ok = py_result != NULL && PyObject_IsTrue(py_result);
|
bool ok = py_result != NULL && PyObject_IsTrue(py_result);
|
||||||
Py_XDECREF(py_result);
|
Py_XDECREF(py_result);
|
||||||
return ok;
|
return ok;
|
||||||
@ -152,9 +164,18 @@ class py_custom_data_type_t
|
|||||||
// Returns: 0-no such item can be created/displayed
|
// Returns: 0-no such item can be created/displayed
|
||||||
// this callback is required only for varsize datatypes
|
// this callback is required only for varsize datatypes
|
||||||
py_custom_data_type_t *_this = (py_custom_data_type_t *)ud;
|
py_custom_data_type_t *_this = (py_custom_data_type_t *)ud;
|
||||||
PyObject *py_result = PyObject_CallMethod(_this->py_self, (char *)S_CALC_ITEM_SIZE, PY_FMT64 PY_FMT64, pyul_t(ea), pyul_t(maxsize));
|
PYW_GIL_ENSURE;
|
||||||
if ( PyW_ShowErr(S_CALC_ITEM_SIZE) || py_result == NULL )
|
PyObject *py_result = PyObject_CallMethod(
|
||||||
|
_this->py_self,
|
||||||
|
(char *)S_CALC_ITEM_SIZE,
|
||||||
|
PY_FMT64 PY_FMT64,
|
||||||
|
pyul_t(ea),
|
||||||
|
pyul_t(maxsize));
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
|
|
||||||
|
if ( PyW_ShowCbErr(S_CALC_ITEM_SIZE) || py_result == NULL )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
uint64 num = 0;
|
uint64 num = 0;
|
||||||
PyW_GetNumber(py_result, &num);
|
PyW_GetNumber(py_result, &num);
|
||||||
Py_XDECREF(py_result);
|
Py_XDECREF(py_result);
|
||||||
@ -189,6 +210,7 @@ public:
|
|||||||
// name
|
// name
|
||||||
if ( !PyW_GetStringAttr(py_obj, S_NAME, &dt_name) )
|
if ( !PyW_GetStringAttr(py_obj, S_NAME, &dt_name) )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
dt.name = dt_name.c_str();
|
dt.name = dt_name.c_str();
|
||||||
|
|
||||||
// menu_name (optional)
|
// menu_name (optional)
|
||||||
@ -293,11 +315,14 @@ private:
|
|||||||
int dtid) // custom data type id
|
int dtid) // custom data type id
|
||||||
{
|
{
|
||||||
// Build a string from the buffer
|
// Build a string from the buffer
|
||||||
PyObject *py_value = PyString_FromStringAndSize((const char *)value, Py_ssize_t(size));
|
PyObject *py_value = PyString_FromStringAndSize(
|
||||||
|
(const char *)value,
|
||||||
|
Py_ssize_t(size));
|
||||||
if ( py_value == NULL )
|
if ( py_value == NULL )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
py_custom_data_format_t *_this = (py_custom_data_format_t *) ud;
|
py_custom_data_format_t *_this = (py_custom_data_format_t *) ud;
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
PyObject *py_result = PyObject_CallMethod(
|
PyObject *py_result = PyObject_CallMethod(
|
||||||
_this->py_self,
|
_this->py_self,
|
||||||
(char *)S_PRINTF,
|
(char *)S_PRINTF,
|
||||||
@ -306,11 +331,12 @@ private:
|
|||||||
pyul_t(current_ea),
|
pyul_t(current_ea),
|
||||||
operand_num,
|
operand_num,
|
||||||
dtid);
|
dtid);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
// Done with the string
|
// Done with the string
|
||||||
Py_DECREF(py_value);
|
Py_DECREF(py_value);
|
||||||
|
|
||||||
// Error while calling the function?
|
// Error while calling the function?
|
||||||
if ( PyW_ShowErr(S_PRINTF) || py_result == NULL )
|
if ( PyW_ShowCbErr(S_PRINTF) || py_result == NULL )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
@ -338,6 +364,7 @@ private:
|
|||||||
qstring *errstr) // buffer for error message
|
qstring *errstr) // buffer for error message
|
||||||
{
|
{
|
||||||
py_custom_data_format_t *_this = (py_custom_data_format_t *) ud;
|
py_custom_data_format_t *_this = (py_custom_data_format_t *) ud;
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
PyObject *py_result = PyObject_CallMethod(
|
PyObject *py_result = PyObject_CallMethod(
|
||||||
_this->py_self,
|
_this->py_self,
|
||||||
(char *)S_SCAN,
|
(char *)S_SCAN,
|
||||||
@ -345,9 +372,10 @@ private:
|
|||||||
input,
|
input,
|
||||||
pyul_t(current_ea),
|
pyul_t(current_ea),
|
||||||
operand_num);
|
operand_num);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
|
|
||||||
// Error while calling the function?
|
// Error while calling the function?
|
||||||
if ( PyW_ShowErr(S_SCAN) || py_result == NULL)
|
if ( PyW_ShowCbErr(S_SCAN) || py_result == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
@ -356,6 +384,7 @@ private:
|
|||||||
// We expect a tuple(bool, string|None)
|
// We expect a tuple(bool, string|None)
|
||||||
if ( !PyTuple_Check(py_result) || PyTuple_Size(py_result) != 2 )
|
if ( !PyTuple_Check(py_result) || PyTuple_Size(py_result) != 2 )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Borrow references
|
// Borrow references
|
||||||
PyObject *py_bool = PyTuple_GetItem(py_result, 0);
|
PyObject *py_bool = PyTuple_GetItem(py_result, 0);
|
||||||
PyObject *py_val = PyTuple_GetItem(py_result, 1);
|
PyObject *py_val = PyTuple_GetItem(py_result, 1);
|
||||||
@ -404,8 +433,17 @@ private:
|
|||||||
// this callback may be missing.
|
// this callback may be missing.
|
||||||
{
|
{
|
||||||
py_custom_data_format_t *_this = (py_custom_data_format_t *) ud;
|
py_custom_data_format_t *_this = (py_custom_data_format_t *) ud;
|
||||||
PyObject *py_result = PyObject_CallMethod(_this->py_self, (char *)S_ANALYZE, PY_FMT64 "i", pyul_t(current_ea),operand_num);
|
|
||||||
PyW_ShowErr(S_ANALYZE);
|
PYW_GIL_ENSURE;
|
||||||
|
PyObject *py_result = PyObject_CallMethod(
|
||||||
|
_this->py_self,
|
||||||
|
(char *)S_ANALYZE,
|
||||||
|
PY_FMT64 "i",
|
||||||
|
pyul_t(current_ea),
|
||||||
|
operand_num);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
|
|
||||||
|
PyW_ShowCbErr(S_ANALYZE);
|
||||||
Py_XDECREF(py_result);
|
Py_XDECREF(py_result);
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
@ -415,7 +453,10 @@ public:
|
|||||||
py_self = NULL;
|
py_self = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *get_name() const { return df_name.c_str(); }
|
const char *get_name() const
|
||||||
|
{
|
||||||
|
return df_name.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
int register_df(int dtid, PyObject *py_obj)
|
int register_df(int dtid, PyObject *py_obj)
|
||||||
{
|
{
|
||||||
@ -491,9 +532,11 @@ public:
|
|||||||
Py_INCREF(py_obj);
|
Py_INCREF(py_obj);
|
||||||
py_self = py_obj;
|
py_self = py_obj;
|
||||||
|
|
||||||
|
// Update the format ID
|
||||||
py_attr = PyInt_FromLong(dfid);
|
py_attr = PyInt_FromLong(dfid);
|
||||||
PyObject_SetAttrString(py_obj, S_ID, py_attr);
|
PyObject_SetAttrString(py_obj, S_ID, py_attr);
|
||||||
Py_DECREF(py_attr);
|
Py_DECREF(py_attr);
|
||||||
|
|
||||||
py_attr = NULL;
|
py_attr = NULL;
|
||||||
} while ( false );
|
} while ( false );
|
||||||
|
|
||||||
|
10
swig/dbg.i
10
swig/dbg.i
@ -10,8 +10,14 @@ typedef struct
|
|||||||
%ignore source_file_t;
|
%ignore source_file_t;
|
||||||
%ignore source_item_t;
|
%ignore source_item_t;
|
||||||
%ignore srcinfo_provider_t;
|
%ignore srcinfo_provider_t;
|
||||||
|
%ignore bpt_location_t::print;
|
||||||
|
%ignore bpt_t::set_cond;
|
||||||
|
%ignore bpt_t::eval_cond;
|
||||||
|
%ignore bpt_t::write;
|
||||||
|
%ignore bpt_t::erase;
|
||||||
%rename (get_manual_regions) py_get_manual_regions;
|
%rename (get_manual_regions) py_get_manual_regions;
|
||||||
%ignore set_manual_regions;
|
%ignore set_manual_regions;
|
||||||
|
%ignore inform_idc_about_debthread;
|
||||||
%include "dbg.hpp"
|
%include "dbg.hpp"
|
||||||
%ignore DBG_Callback;
|
%ignore DBG_Callback;
|
||||||
%feature("director") DBG_Hooks;
|
%feature("director") DBG_Hooks;
|
||||||
@ -75,8 +81,12 @@ static PyObject *refresh_debugger_memory()
|
|||||||
{
|
{
|
||||||
invalidate_dbgmem_config();
|
invalidate_dbgmem_config();
|
||||||
invalidate_dbgmem_contents(BADADDR, 0);
|
invalidate_dbgmem_contents(BADADDR, 0);
|
||||||
|
|
||||||
|
// Ask the debugger to populate debug names
|
||||||
if ( dbg != NULL && dbg->stopped_at_debug_event != NULL )
|
if ( dbg != NULL && dbg->stopped_at_debug_event != NULL )
|
||||||
dbg->stopped_at_debug_event(true);
|
dbg->stopped_at_debug_event(true);
|
||||||
|
|
||||||
|
// Invalidate the cache
|
||||||
isEnabled(0);
|
isEnabled(0);
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
@ -49,7 +49,12 @@
|
|||||||
int idaapi py_enumerate_files_cb(const char *file, void *ud)
|
int idaapi py_enumerate_files_cb(const char *file, void *ud)
|
||||||
{
|
{
|
||||||
PyObject *py_file = PyString_FromString(file);
|
PyObject *py_file = PyString_FromString(file);
|
||||||
PyObject *py_ret = PyObject_CallFunctionObjArgs((PyObject *)ud, py_file, NULL);
|
PYW_GIL_ENSURE;
|
||||||
|
PyObject *py_ret = PyObject_CallFunctionObjArgs(
|
||||||
|
(PyObject *)ud,
|
||||||
|
py_file,
|
||||||
|
NULL);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
int r = (py_ret == NULL || !PyNumber_Check(py_ret)) ? 1 /* stop enumeration on failure */ : PyInt_AsLong(py_ret);
|
int r = (py_ret == NULL || !PyNumber_Check(py_ret)) ? 1 /* stop enumeration on failure */ : PyInt_AsLong(py_ret);
|
||||||
Py_XDECREF(py_file);
|
Py_XDECREF(py_file);
|
||||||
Py_XDECREF(py_ret);
|
Py_XDECREF(py_ret);
|
||||||
|
13
swig/expr.i
13
swig/expr.i
@ -35,15 +35,17 @@
|
|||||||
%ignore expr_printf;
|
%ignore expr_printf;
|
||||||
%ignore expr_sprintf;
|
%ignore expr_sprintf;
|
||||||
%ignore expr_printfer;
|
%ignore expr_printfer;
|
||||||
%ignore idaapi init_idc;
|
%ignore init_idc;
|
||||||
%ignore idaapi term_idc;
|
%ignore term_idc;
|
||||||
%ignore del_idc_userfuncs;
|
%ignore create_default_idc_classes;
|
||||||
%ignore del_idc_userdefs;
|
%ignore insn_to_idc;
|
||||||
%ignore find_builtin_idc_func;
|
%ignore find_builtin_idc_func;
|
||||||
|
%ignore idc_mutex;
|
||||||
%ignore idc_lx;
|
%ignore idc_lx;
|
||||||
%ignore idc_vars;
|
%ignore idc_vars;
|
||||||
%ignore idc_resolve_label;
|
%ignore idc_resolve_label;
|
||||||
%ignore idc_resolver_ea;
|
%ignore idc_resolver_ea;
|
||||||
|
%ignore setup_lowcnd_regfuncs;
|
||||||
|
|
||||||
%cstring_output_maxstr_none(char *errbuf, size_t errbufsize);
|
%cstring_output_maxstr_none(char *errbuf, size_t errbufsize);
|
||||||
|
|
||||||
@ -83,12 +85,13 @@ bool calc_idc_expr_wrap(ea_t where,const char *line, idc_value_t *rv, char *errb
|
|||||||
%}
|
%}
|
||||||
|
|
||||||
%ignore CompileLine(const char *line, char *errbuf, size_t errbufsize, uval_t (idaapi*_getname)(const char *name)=NULL);
|
%ignore CompileLine(const char *line, char *errbuf, size_t errbufsize, uval_t (idaapi*_getname)(const char *name)=NULL);
|
||||||
|
%ignore CompileLineEx;
|
||||||
|
|
||||||
%rename (CompileLine) CompileLine_wrap;
|
%rename (CompileLine) CompileLine_wrap;
|
||||||
%inline %{
|
%inline %{
|
||||||
bool CompileLine_wrap(const char *line, char *errbuf, size_t errbufsize)
|
bool CompileLine_wrap(const char *line, char *errbuf, size_t errbufsize)
|
||||||
{
|
{
|
||||||
return !CompileLine(line, errbuf, errbufsize);
|
return !CompileLineEx(line, errbuf, errbufsize);
|
||||||
}
|
}
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
32
swig/funcs.i
32
swig/funcs.i
@ -27,6 +27,7 @@
|
|||||||
%ignore create_func_eas_array;
|
%ignore create_func_eas_array;
|
||||||
%ignore auto_add_func_tails;
|
%ignore auto_add_func_tails;
|
||||||
%ignore read_tails;
|
%ignore read_tails;
|
||||||
|
%rename (get_idasgn_desc) py_get_idasgn_desc;
|
||||||
|
|
||||||
%include "funcs.hpp"
|
%include "funcs.hpp"
|
||||||
|
|
||||||
@ -34,18 +35,47 @@
|
|||||||
%clear(char *optlibs);
|
%clear(char *optlibs);
|
||||||
|
|
||||||
%inline %{
|
%inline %{
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
/*
|
/*
|
||||||
#<pydoc>
|
#<pydoc>
|
||||||
def get_fchunk_referer(ea, idx):
|
def get_fchunk_referer(ea, idx):
|
||||||
pass
|
pass
|
||||||
#</pydoc>
|
#</pydoc>
|
||||||
*/
|
*/
|
||||||
ea_t get_fchunk_referer(ea_t ea, size_t idx)
|
static ea_t get_fchunk_referer(ea_t ea, size_t idx)
|
||||||
{
|
{
|
||||||
func_t *pfn = get_fchunk(ea);
|
func_t *pfn = get_fchunk(ea);
|
||||||
func_parent_iterator_t dummy(pfn); // read referer info
|
func_parent_iterator_t dummy(pfn); // read referer info
|
||||||
if (idx >= pfn->refqty || pfn->referers == NULL)
|
if (idx >= pfn->refqty || pfn->referers == NULL)
|
||||||
return BADADDR;
|
return BADADDR;
|
||||||
|
else
|
||||||
return pfn->referers[idx];
|
return pfn->referers[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
#<pydoc>
|
||||||
|
def get_idasgn_desc(n):
|
||||||
|
"""
|
||||||
|
Get information about a signature in the list.
|
||||||
|
It returns both:
|
||||||
|
signame - the name of the signature
|
||||||
|
optlibs - the names of the optional libraries
|
||||||
|
|
||||||
|
@param n: number of signature in the list (0..get_idasgn_qty()-1)
|
||||||
|
@return: None on failure or tuple(signame, optlibs)
|
||||||
|
"""
|
||||||
|
#</pydoc>
|
||||||
|
*/
|
||||||
|
static PyObject *ida_export py_get_idasgn_desc(int n)
|
||||||
|
{
|
||||||
|
char signame[MAXSTR];
|
||||||
|
char optlibs[MAXSTR];
|
||||||
|
|
||||||
|
if ( get_idasgn_desc(n, signame, sizeof(signame), optlibs, sizeof(optlibs)) == -1 )
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
else
|
||||||
|
return Py_BuildValue("(ss)", signame, optlibs);
|
||||||
|
}
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
12
swig/gdl.i
12
swig/gdl.i
@ -91,6 +91,14 @@ class FlowChart(object):
|
|||||||
self._q.refresh()
|
self._q.refresh()
|
||||||
|
|
||||||
|
|
||||||
|
def _getitem(self, index):
|
||||||
|
return BasicBlock(index, self._q[index], self)
|
||||||
|
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return (self._getitem(index) for index in xrange(0, self.size))
|
||||||
|
|
||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, index):
|
||||||
"""
|
"""
|
||||||
Returns a basic block
|
Returns a basic block
|
||||||
@ -98,9 +106,9 @@ class FlowChart(object):
|
|||||||
@return: BasicBlock
|
@return: BasicBlock
|
||||||
"""
|
"""
|
||||||
if index >= self.size:
|
if index >= self.size:
|
||||||
raise StopIteration
|
raise KeyError
|
||||||
else:
|
else:
|
||||||
return BasicBlock(index, self._q[index], self)
|
return self._getitem(index)
|
||||||
|
|
||||||
#</pycode(py_gdl)>
|
#</pycode(py_gdl)>
|
||||||
%}
|
%}
|
||||||
|
130
swig/graph.i
130
swig/graph.i
@ -2,26 +2,6 @@
|
|||||||
%ignore graph_visitor_t;
|
%ignore graph_visitor_t;
|
||||||
%ignore abstract_graph_t;
|
%ignore abstract_graph_t;
|
||||||
|
|
||||||
%{
|
|
||||||
#ifdef __GNUC__
|
|
||||||
// for some reason GCC insists on putting the vtable into the object file,
|
|
||||||
// even though we only use mutable_graph_t by pointer
|
|
||||||
// so we define these methods here to make the linker happy
|
|
||||||
|
|
||||||
edge_info_t *idaapi mutable_graph_t::get_edge(edge_t e) { INTERR(); };
|
|
||||||
mutable_graph_t *idaapi mutable_graph_t::clone(void) const { INTERR(); };
|
|
||||||
bool idaapi mutable_graph_t::redo_layout(void) { INTERR(); };
|
|
||||||
void idaapi mutable_graph_t::resize(int n) { INTERR(); };
|
|
||||||
int idaapi mutable_graph_t::add_node(const rect_t *r) { INTERR(); };
|
|
||||||
ssize_t idaapi mutable_graph_t::del_node(int n) { INTERR(); };
|
|
||||||
bool idaapi mutable_graph_t::add_edge(int i, int j, const edge_info_t *ei) { INTERR(); };
|
|
||||||
bool idaapi mutable_graph_t::del_edge(int i, int j) { INTERR(); };
|
|
||||||
bool idaapi mutable_graph_t::replace_edge(int i, int j, int x, int y) { INTERR(); };
|
|
||||||
bool idaapi mutable_graph_t::refresh(void) { INTERR(); };
|
|
||||||
bool idaapi mutable_graph_t::set_nrect(int n, const rect_t &r) { INTERR(); };
|
|
||||||
#endif
|
|
||||||
%}
|
|
||||||
|
|
||||||
%{
|
%{
|
||||||
//<code(py_graph)>
|
//<code(py_graph)>
|
||||||
class py_graph_t
|
class py_graph_t
|
||||||
@ -46,6 +26,7 @@ private:
|
|||||||
nodetext_cache_t(const char *t, bgcolor_t c): text(t), bgcolor(c) { }
|
nodetext_cache_t(const char *t, bgcolor_t c): text(t), bgcolor(c) { }
|
||||||
nodetext_cache_t() { }
|
nodetext_cache_t() { }
|
||||||
};
|
};
|
||||||
|
|
||||||
class nodetext_cache_map_t: public std::map<int, nodetext_cache_t>
|
class nodetext_cache_map_t: public std::map<int, nodetext_cache_t>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -75,6 +56,7 @@ private:
|
|||||||
(*this)[form] = py;
|
(*this)[form] = py;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class cmdid_map_t: public std::map<Py_ssize_t, py_graph_t *>
|
class cmdid_map_t: public std::map<Py_ssize_t, py_graph_t *>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@ -83,7 +65,8 @@ private:
|
|||||||
|
|
||||||
cmdid_map_t()
|
cmdid_map_t()
|
||||||
{
|
{
|
||||||
uid = 1; // we start by one and keep zero for error id
|
// We start by one and keep zero for error id
|
||||||
|
uid = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add(py_graph_t *pyg)
|
void add(py_graph_t *pyg)
|
||||||
@ -92,7 +75,10 @@ private:
|
|||||||
++uid;
|
++uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Py_ssize_t id() const { return uid; }
|
const Py_ssize_t id() const
|
||||||
|
{
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
void clear(py_graph_t *pyg)
|
void clear(py_graph_t *pyg)
|
||||||
{
|
{
|
||||||
@ -108,6 +94,7 @@ private:
|
|||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
py_graph_t *get(Py_ssize_t id)
|
py_graph_t *get(Py_ssize_t id)
|
||||||
{
|
{
|
||||||
iterator it = find(id);
|
iterator it = find(id);
|
||||||
@ -136,13 +123,16 @@ private:
|
|||||||
py_graph_t *_this = cmdid_pyg.get(id);
|
py_graph_t *_this = cmdid_pyg.get(id);
|
||||||
if ( _this != NULL )
|
if ( _this != NULL )
|
||||||
_this->on_command(id);
|
_this->on_command(id);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_command(Py_ssize_t id)
|
void on_command(Py_ssize_t id)
|
||||||
{
|
{
|
||||||
// Check return value to OnRefresh() call
|
// Check return value to OnRefresh() call
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
PyObject *ret = PyObject_CallMethod(self, (char *)S_ON_COMMAND, "n", id);
|
PyObject *ret = PyObject_CallMethod(self, (char *)S_ON_COMMAND, "n", id);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
Py_XDECREF(ret);
|
Py_XDECREF(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +145,9 @@ private:
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Check return value to OnRefresh() call
|
// Check return value to OnRefresh() call
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
PyObject *ret = PyObject_CallMethod(self, (char *)S_ON_REFRESH, NULL);
|
PyObject *ret = PyObject_CallMethod(self, (char *)S_ON_REFRESH, NULL);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
if ( ret == NULL || !PyObject_IsTrue(ret) )
|
if ( ret == NULL || !PyObject_IsTrue(ret) )
|
||||||
{
|
{
|
||||||
Py_XDECREF(ret);
|
Py_XDECREF(ret);
|
||||||
@ -213,11 +205,14 @@ private:
|
|||||||
Py_DECREF(id);
|
Py_DECREF(id);
|
||||||
if ( v > max_nodes )
|
if ( v > max_nodes )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
edge_ids[j] = v;
|
edge_ids[j] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Incomplete?
|
// Incomplete?
|
||||||
if ( j != qnumber(edge_ids) )
|
if ( j != qnumber(edge_ids) )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Add the edge
|
// Add the edge
|
||||||
g->add_edge(edge_ids[0], edge_ids[1], NULL);
|
g->add_edge(edge_ids[0], edge_ids[1], NULL);
|
||||||
}
|
}
|
||||||
@ -240,7 +235,9 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Not cached, call Python
|
// Not cached, call Python
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_GETTEXT, "i", node);
|
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_GETTEXT, "i", node);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
if ( result == NULL )
|
if ( result == NULL )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -276,6 +273,7 @@ private:
|
|||||||
*str = c->text.c_str();
|
*str = c->text.c_str();
|
||||||
if ( bg_color != NULL )
|
if ( bg_color != NULL )
|
||||||
*bg_color = c->bgcolor;
|
*bg_color = c->bgcolor;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,7 +288,9 @@ private:
|
|||||||
if ( mousenode == -1 )
|
if ( mousenode == -1 )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_HINT, "i", mousenode);
|
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_HINT, "i", mousenode);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
bool ok = result != NULL && PyString_Check(result);
|
bool ok = result != NULL && PyString_Check(result);
|
||||||
if ( !ok )
|
if ( !ok )
|
||||||
{
|
{
|
||||||
@ -307,24 +307,33 @@ private:
|
|||||||
{
|
{
|
||||||
if ( self != NULL )
|
if ( self != NULL )
|
||||||
{
|
{
|
||||||
if ( cb_flags & GR_HAVE_CLOSE )
|
if ( (cb_flags & GR_HAVE_CLOSE) != 0 )
|
||||||
{
|
{
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_CLOSE, NULL);
|
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_CLOSE, NULL);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
|
|
||||||
Py_XDECREF(result);
|
Py_XDECREF(result);
|
||||||
}
|
}
|
||||||
unbind();
|
unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the TForm from list
|
// Remove the TForm from list
|
||||||
if ( form != NULL )
|
if ( form != NULL )
|
||||||
tform_pyg.erase(form);
|
tform_pyg.erase(form);
|
||||||
// remove all associated commands from the list
|
|
||||||
|
// Remove all associated commands from the list
|
||||||
cmdid_pyg.clear(this);
|
cmdid_pyg.clear(this);
|
||||||
|
|
||||||
// Delete this instance
|
// Delete this instance
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// graph is being clicked
|
// graph is being clicked
|
||||||
int on_clicked(graph_viewer_t * /*gv*/, selection_item_t * /*item1*/, graph_item_t *item2)
|
int on_clicked(
|
||||||
|
graph_viewer_t * /*gv*/,
|
||||||
|
selection_item_t * /*item1*/,
|
||||||
|
graph_item_t *item2)
|
||||||
{
|
{
|
||||||
// in: graph_viewer_t *gv
|
// in: graph_viewer_t *gv
|
||||||
// selection_item_t *current_item1
|
// selection_item_t *current_item1
|
||||||
@ -338,7 +347,14 @@ private:
|
|||||||
if ( item2->n == -1 )
|
if ( item2->n == -1 )
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_CLICK, "i", item2->n);
|
PYW_GIL_ENSURE;
|
||||||
|
PyObject *result = PyObject_CallMethod(
|
||||||
|
self,
|
||||||
|
(char *)S_ON_CLICK,
|
||||||
|
"i",
|
||||||
|
item2->n);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
|
|
||||||
if ( result == NULL || !PyObject_IsTrue(result) )
|
if ( result == NULL || !PyObject_IsTrue(result) )
|
||||||
{
|
{
|
||||||
Py_XDECREF(result);
|
Py_XDECREF(result);
|
||||||
@ -360,7 +376,15 @@ private:
|
|||||||
//selection_item_t *s = va_arg(va, selection_item_t *);
|
//selection_item_t *s = va_arg(va, selection_item_t *);
|
||||||
if ( item == NULL || !item->is_node )
|
if ( item == NULL || !item->is_node )
|
||||||
return 1;
|
return 1;
|
||||||
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_DBL_CLICK, "i", item->node);
|
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
|
PyObject *result = PyObject_CallMethod(
|
||||||
|
self,
|
||||||
|
(char *)S_ON_DBL_CLICK,
|
||||||
|
"i",
|
||||||
|
item->node);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
|
|
||||||
if ( result == NULL || !PyObject_IsTrue(result) )
|
if ( result == NULL || !PyObject_IsTrue(result) )
|
||||||
{
|
{
|
||||||
Py_XDECREF(result);
|
Py_XDECREF(result);
|
||||||
@ -373,14 +397,25 @@ private:
|
|||||||
// a graph viewer got focus
|
// a graph viewer got focus
|
||||||
void on_gotfocus(graph_viewer_t * /*gv*/)
|
void on_gotfocus(graph_viewer_t * /*gv*/)
|
||||||
{
|
{
|
||||||
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_ACTIVATE, NULL);
|
PYW_GIL_ENSURE;
|
||||||
|
PyObject *result = PyObject_CallMethod(
|
||||||
|
self,
|
||||||
|
(char *)S_ON_ACTIVATE,
|
||||||
|
NULL);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
Py_XDECREF(result);
|
Py_XDECREF(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// a graph viewer lost focus
|
// a graph viewer lost focus
|
||||||
void on_lostfocus(graph_viewer_t *gv)
|
void on_lostfocus(graph_viewer_t *gv)
|
||||||
{
|
{
|
||||||
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_DEACTIVATE, NULL);
|
PYW_GIL_ENSURE;
|
||||||
|
PyObject *result = PyObject_CallMethod(
|
||||||
|
self,
|
||||||
|
(char *)S_ON_DEACTIVATE,
|
||||||
|
NULL);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
|
|
||||||
Py_XDECREF(result);
|
Py_XDECREF(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,7 +427,15 @@ private:
|
|||||||
// out: 0-ok, 1-forbid to change the current node
|
// out: 0-ok, 1-forbid to change the current node
|
||||||
if ( curnode < 0 )
|
if ( curnode < 0 )
|
||||||
return 0;
|
return 0;
|
||||||
PyObject *result = PyObject_CallMethod(self, (char *)S_ON_SELECT, "i", curnode);
|
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
|
PyObject *result = PyObject_CallMethod(
|
||||||
|
self,
|
||||||
|
(char *)S_ON_SELECT,
|
||||||
|
"i",
|
||||||
|
curnode);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
|
|
||||||
bool allow = (result != NULL && PyObject_IsTrue(result));
|
bool allow = (result != NULL && PyObject_IsTrue(result));
|
||||||
Py_XDECREF(result);
|
Py_XDECREF(result);
|
||||||
return allow ? 0 : 1;
|
return allow ? 0 : 1;
|
||||||
@ -428,7 +471,10 @@ private:
|
|||||||
ret = on_clicked(gv, item, gitem);
|
ret = on_clicked(gv, item, gitem);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ret = 1; // ignore click
|
{
|
||||||
|
// Ignore the click
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
//
|
//
|
||||||
case grcode_dblclicked:
|
case grcode_dblclicked:
|
||||||
@ -445,17 +491,20 @@ private:
|
|||||||
case grcode_gotfocus:
|
case grcode_gotfocus:
|
||||||
if ( cb_flags & GR_HAVE_GOTFOCUS )
|
if ( cb_flags & GR_HAVE_GOTFOCUS )
|
||||||
on_gotfocus(va_arg(va, graph_viewer_t *));
|
on_gotfocus(va_arg(va, graph_viewer_t *));
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
//
|
//
|
||||||
case grcode_lostfocus:
|
case grcode_lostfocus:
|
||||||
if ( cb_flags & GR_HAVE_LOSTFOCUS )
|
if ( cb_flags & GR_HAVE_LOSTFOCUS )
|
||||||
on_lostfocus(va_arg(va, graph_viewer_t *));
|
on_lostfocus(va_arg(va, graph_viewer_t *));
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
//
|
//
|
||||||
case grcode_user_refresh:
|
case grcode_user_refresh:
|
||||||
on_user_refresh(va_arg(va, mutable_graph_t *));
|
on_user_refresh(va_arg(va, mutable_graph_t *));
|
||||||
|
|
||||||
ret = 1;
|
ret = 1;
|
||||||
break;
|
break;
|
||||||
//
|
//
|
||||||
@ -617,7 +666,7 @@ private:
|
|||||||
netnode id;
|
netnode id;
|
||||||
id.create();
|
id.create();
|
||||||
gv = create_graph_viewer(form, id, s_callback, this, 0);
|
gv = create_graph_viewer(form, id, s_callback, this, 0);
|
||||||
open_tform(form, FORM_MDI|FORM_TAB|FORM_MENU);
|
open_tform(form, FORM_MDI | FORM_TAB | FORM_MENU);
|
||||||
if ( gv != NULL )
|
if ( gv != NULL )
|
||||||
viewer_fit_window(gv);
|
viewer_fit_window(gv);
|
||||||
}
|
}
|
||||||
@ -625,6 +674,7 @@ private:
|
|||||||
{
|
{
|
||||||
show();
|
show();
|
||||||
}
|
}
|
||||||
|
|
||||||
viewer_fit_window(gv);
|
viewer_fit_window(gv);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -655,6 +705,7 @@ private:
|
|||||||
py_graph_t *_this = extract_this(self);
|
py_graph_t *_this = extract_this(self);
|
||||||
if ( _this == NULL || _this->form == NULL )
|
if ( _this == NULL || _this->form == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_this->jump_to_node(0);
|
_this->jump_to_node(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -663,6 +714,7 @@ private:
|
|||||||
py_graph_t *_this = extract_this(self);
|
py_graph_t *_this = extract_this(self);
|
||||||
if ( _this == NULL || _this->form == NULL )
|
if ( _this == NULL || _this->form == NULL )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return _this->add_command(title, hotkey);
|
return _this->add_command(title, hotkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -671,6 +723,7 @@ private:
|
|||||||
py_graph_t *_this = extract_this(self);
|
py_graph_t *_this = extract_this(self);
|
||||||
if ( _this == NULL || _this->form == NULL )
|
if ( _this == NULL || _this->form == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
close_tform(_this->form, 0);
|
close_tform(_this->form, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -679,6 +732,7 @@ private:
|
|||||||
py_graph_t *_this = extract_this(self);
|
py_graph_t *_this = extract_this(self);
|
||||||
if ( _this == NULL )
|
if ( _this == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_this->refresh();
|
_this->refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -763,7 +817,7 @@ bool pyg_show(PyObject *self);
|
|||||||
|
|
||||||
%pythoncode %{
|
%pythoncode %{
|
||||||
#<pycode(py_graph)>
|
#<pycode(py_graph)>
|
||||||
class GraphViewer:
|
class GraphViewer(object):
|
||||||
"""This class wraps the user graphing facility provided by the graph.hpp file"""
|
"""This class wraps the user graphing facility provided by the graph.hpp file"""
|
||||||
def __init__(self, title, close_open = False):
|
def __init__(self, title, close_open = False):
|
||||||
"""
|
"""
|
||||||
@ -793,10 +847,16 @@ class GraphViewer:
|
|||||||
self._nodes = []
|
self._nodes = []
|
||||||
self._edges = []
|
self._edges = []
|
||||||
|
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return (self._nodes[index] for index in xrange(0, len(self._nodes)))
|
||||||
|
|
||||||
|
|
||||||
def __getitem__(self, idx):
|
def __getitem__(self, idx):
|
||||||
"""Returns a reference to the object associated with this node id"""
|
"""Returns a reference to the object associated with this node id"""
|
||||||
if idx > len(self._nodes):
|
if idx >= len(self._nodes):
|
||||||
raise StopIteration
|
raise KeyError
|
||||||
|
else:
|
||||||
return self._nodes[idx]
|
return self._nodes[idx]
|
||||||
|
|
||||||
def Count(self):
|
def Count(self):
|
||||||
|
2505
swig/idaapi.i
2505
swig/idaapi.i
File diff suppressed because it is too large
Load Diff
19
swig/idd.i
19
swig/idd.i
@ -85,7 +85,9 @@ PyObject *py_appcall(
|
|||||||
// Set exception message
|
// Set exception message
|
||||||
if ( !ok )
|
if ( !ok )
|
||||||
{
|
{
|
||||||
PyErr_SetString(PyExc_ValueError, "PyAppCall: Failed to convert Python values to IDC values");
|
PyErr_SetString(
|
||||||
|
PyExc_ValueError,
|
||||||
|
"PyAppCall: Failed to convert Python values to IDC values");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,6 +95,7 @@ PyObject *py_appcall(
|
|||||||
{
|
{
|
||||||
msg("input variables:\n"
|
msg("input variables:\n"
|
||||||
"----------------\n");
|
"----------------\n");
|
||||||
|
|
||||||
qstring s;
|
qstring s;
|
||||||
for ( Py_ssize_t i=0; i<nargs; i++ )
|
for ( Py_ssize_t i=0; i<nargs; i++ )
|
||||||
{
|
{
|
||||||
@ -101,6 +104,7 @@ PyObject *py_appcall(
|
|||||||
s.qclear();
|
s.qclear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do Appcall
|
// Do Appcall
|
||||||
idc_value_t idc_result;
|
idc_value_t idc_result;
|
||||||
error_t ret = appcall(
|
error_t ret = appcall(
|
||||||
@ -146,6 +150,7 @@ PyObject *py_appcall(
|
|||||||
s.qclear();
|
s.qclear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert IDC values back to Python values
|
// Convert IDC values back to Python values
|
||||||
for ( Py_ssize_t i=0; i<nargs; i++ )
|
for ( Py_ssize_t i=0; i<nargs; i++ )
|
||||||
{
|
{
|
||||||
@ -268,6 +273,7 @@ static PyObject *dbg_get_thread_sreg_base(PyObject *py_tid, PyObject *py_sreg_va
|
|||||||
int sreg_value = PyInt_AsLong(py_sreg_value);
|
int sreg_value = PyInt_AsLong(py_sreg_value);
|
||||||
if ( dbg->thread_get_sreg_base(tid, sreg_value, &answer) != 1 )
|
if ( dbg->thread_get_sreg_base(tid, sreg_value, &answer) != 1 )
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
return Py_BuildValue(PY_FMT64, pyul_t(answer));
|
return Py_BuildValue(PY_FMT64, pyul_t(answer));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -620,6 +626,7 @@ class Appcall_callable__(object):
|
|||||||
fields = property(__get_fields)
|
fields = property(__get_fields)
|
||||||
"""Returns the field names"""
|
"""Returns the field names"""
|
||||||
|
|
||||||
|
|
||||||
def retrieve(self, src=None, flags=0):
|
def retrieve(self, src=None, flags=0):
|
||||||
"""
|
"""
|
||||||
Unpacks a typed object from the database if an ea is given or from a string if a string was passed
|
Unpacks a typed object from the database if an ea is given or from a string if a string was passed
|
||||||
@ -628,7 +635,7 @@ class Appcall_callable__(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Nothing passed? Take the address and unpack from the database
|
# Nothing passed? Take the address and unpack from the database
|
||||||
if not src:
|
if src is None:
|
||||||
src = self.ea
|
src = self.ea
|
||||||
|
|
||||||
if type(src) == types.StringType:
|
if type(src) == types.StringType:
|
||||||
@ -740,11 +747,11 @@ class Appcall__(object):
|
|||||||
# resolve and raise exception on error
|
# resolve and raise exception on error
|
||||||
ea = Appcall__.__name_or_ea(name_or_ea)
|
ea = Appcall__.__name_or_ea(name_or_ea)
|
||||||
# parse the type
|
# parse the type
|
||||||
if not flags:
|
if flags is None:
|
||||||
flags = 1 | 2 | 4 # PT_SIL | PT_NDC | PT_TYP
|
flags = 1 | 2 | 4 # PT_SIL | PT_NDC | PT_TYP
|
||||||
|
|
||||||
result = _idaapi.idc_parse_decl(_idaapi.cvar.idati, prototype, flags)
|
result = _idaapi.idc_parse_decl(_idaapi.cvar.idati, prototype, flags)
|
||||||
if not result:
|
if result is None:
|
||||||
raise ValueError, "Could not parse type: " + prototype
|
raise ValueError, "Could not parse type: " + prototype
|
||||||
|
|
||||||
# Return the callable method with type info
|
# Return the callable method with type info
|
||||||
@ -797,7 +804,7 @@ class Appcall__(object):
|
|||||||
Creates a string buffer. The returned value (r) will be a byref object.
|
Creates a string buffer. The returned value (r) will be a byref object.
|
||||||
Use r.value to get the contents and r.size to get the buffer's size
|
Use r.value to get the contents and r.size to get the buffer's size
|
||||||
"""
|
"""
|
||||||
if not str:
|
if str is None:
|
||||||
str = ""
|
str = ""
|
||||||
left = size - len(str)
|
left = size - len(str)
|
||||||
if left > 0:
|
if left > 0:
|
||||||
@ -834,7 +841,7 @@ class Appcall__(object):
|
|||||||
"""
|
"""
|
||||||
# parse the type
|
# parse the type
|
||||||
result = _idaapi.idc_parse_decl(_idaapi.cvar.idati, typestr, 1 | 2 | 4) # PT_SIL | PT_NDC | PT_TYP
|
result = _idaapi.idc_parse_decl(_idaapi.cvar.idati, typestr, 1 | 2 | 4) # PT_SIL | PT_NDC | PT_TYP
|
||||||
if not result:
|
if result is None:
|
||||||
raise ValueError, "Could not parse type: " + typestr
|
raise ValueError, "Could not parse type: " + typestr
|
||||||
# Return the callable method with type info
|
# Return the callable method with type info
|
||||||
return Appcall_callable__(ea, result[1], result[2])
|
return Appcall_callable__(ea, result[1], result[2])
|
||||||
|
600
swig/idp.i
600
swig/idp.i
@ -42,72 +42,6 @@
|
|||||||
%feature("director") IDB_Hooks;
|
%feature("director") IDB_Hooks;
|
||||||
%feature("director") IDP_Hooks;
|
%feature("director") IDP_Hooks;
|
||||||
%inline %{
|
%inline %{
|
||||||
int idaapi IDB_Callback(void *ud, int notification_code, va_list va);
|
|
||||||
class IDB_Hooks
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~IDB_Hooks() {};
|
|
||||||
|
|
||||||
bool hook() { return hook_to_notification_point(HT_IDB, IDB_Callback, this); }
|
|
||||||
bool unhook() { return unhook_from_notification_point(HT_IDB, IDB_Callback, this); }
|
|
||||||
/* Hook functions to override in Python */
|
|
||||||
virtual int byte_patched(ea_t ea) { return 0; };
|
|
||||||
virtual int cmt_changed(ea_t, bool repeatable_cmt) { return 0; };
|
|
||||||
virtual int ti_changed(ea_t ea, const type_t *type, const p_list *fnames) { msg("ti_changed hook not supported yet\n"); return 0; };
|
|
||||||
virtual int op_ti_changed(ea_t ea, int n, const type_t *type, const p_list *fnames) { msg("op_ti_changed hook not supported yet\n"); return 0; };
|
|
||||||
virtual int op_type_changed(ea_t ea, int n) { return 0; };
|
|
||||||
virtual int enum_created(enum_t id) { return 0; };
|
|
||||||
virtual int enum_deleted(enum_t id) { return 0; };
|
|
||||||
virtual int enum_bf_changed(enum_t id) { return 0; };
|
|
||||||
virtual int enum_renamed(enum_t id) { return 0; };
|
|
||||||
virtual int enum_cmt_changed(enum_t id) { return 0; };
|
|
||||||
virtual int enum_member_created(enum_t id, const_t cid) { return 0; };
|
|
||||||
virtual int enum_member_deleted(enum_t id, const_t cid) { return 0; };
|
|
||||||
virtual int struc_created(tid_t struc_id) { return 0; };
|
|
||||||
virtual int struc_deleted(tid_t struc_id) { return 0; };
|
|
||||||
virtual int struc_renamed(struc_t *sptr) { return 0; };
|
|
||||||
virtual int struc_expanded(struc_t *sptr) { return 0; };
|
|
||||||
virtual int struc_cmt_changed(tid_t struc_id) { return 0; };
|
|
||||||
virtual int struc_member_created(struc_t *sptr, member_t *mptr) { return 0; };
|
|
||||||
virtual int struc_member_deleted(struc_t *sptr, tid_t member_id) { return 0; };
|
|
||||||
virtual int struc_member_renamed(struc_t *sptr, member_t *mptr) { return 0; };
|
|
||||||
virtual int struc_member_changed(struc_t *sptr, member_t *mptr) { return 0; };
|
|
||||||
virtual int thunk_func_created(func_t *pfn) { return 0; };
|
|
||||||
virtual int func_tail_appended(func_t *pfn, func_t *tail) { return 0; };
|
|
||||||
virtual int func_tail_removed(func_t *pfn, ea_t tail_ea) { return 0; };
|
|
||||||
virtual int tail_owner_changed(func_t *tail, ea_t owner_func) { return 0; };
|
|
||||||
virtual int func_noret_changed(func_t *pfn) { return 0; };
|
|
||||||
virtual int segm_added(segment_t *s) { return 0; };
|
|
||||||
virtual int segm_deleted(ea_t startEA) { return 0; };
|
|
||||||
virtual int segm_start_changed(segment_t *s) { return 0; };
|
|
||||||
virtual int segm_end_changed(segment_t *s) { return 0; };
|
|
||||||
virtual int segm_moved(ea_t from, ea_t to, asize_t size) { return 0; };
|
|
||||||
};
|
|
||||||
|
|
||||||
// Assemble an instruction into the database (display a warning if an error is found)
|
|
||||||
// args:
|
|
||||||
// ea_t ea - linear address of instruction
|
|
||||||
// ea_t cs - cs of instruction
|
|
||||||
// ea_t ip - ip of instruction
|
|
||||||
// bool use32 - is 32bit segment?
|
|
||||||
// const char *line - line to assemble
|
|
||||||
// returns: 1: success, 0: failure
|
|
||||||
inline const int assemble(ea_t ea, ea_t cs, ea_t ip, bool use32, const char *line)
|
|
||||||
{
|
|
||||||
int inslen;
|
|
||||||
char buf[MAXSTR];
|
|
||||||
|
|
||||||
if (ph.notify != NULL)
|
|
||||||
{
|
|
||||||
inslen = ph.notify(ph.assemble, ea, cs, ip, use32, line, buf);
|
|
||||||
if (inslen > 0)
|
|
||||||
{
|
|
||||||
patch_many_bytes(ea, buf, inslen);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//<inline(py_idp)>
|
//<inline(py_idp)>
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
@ -117,7 +51,7 @@ inline const int assemble(ea_t ea, ea_t cs, ea_t ip, bool use32, const char *lin
|
|||||||
#<pydoc>
|
#<pydoc>
|
||||||
def AssembleLine(ea, cs, ip, use32, line):
|
def AssembleLine(ea, cs, ip, use32, line):
|
||||||
"""
|
"""
|
||||||
Assemble an instruction to a buffer (display a warning if an error is found)
|
Assemble an instruction to a string (display a warning if an error is found)
|
||||||
|
|
||||||
@param ea: linear address of instruction
|
@param ea: linear address of instruction
|
||||||
@param cs: cs of instruction
|
@param cs: cs of instruction
|
||||||
@ -143,6 +77,39 @@ static PyObject *AssembleLine(ea_t ea, ea_t cs, ea_t ip, bool use32, const char
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
#<pydoc>
|
||||||
|
def assemble(ea, cs, ip, use32, line):
|
||||||
|
"""
|
||||||
|
Assemble an instruction into the database (display a warning if an error is found)
|
||||||
|
@param ea: linear address of instruction
|
||||||
|
@param cs: cs of instruction
|
||||||
|
@param ip: ip of instruction
|
||||||
|
@param use32: is 32bit segment?
|
||||||
|
@param line: line to assemble
|
||||||
|
|
||||||
|
@return: Boolean. True on success.
|
||||||
|
"""
|
||||||
|
#</pydoc>
|
||||||
|
*/
|
||||||
|
bool assemble(ea_t ea, ea_t cs, ea_t ip, bool use32, const char *line)
|
||||||
|
{
|
||||||
|
int inslen;
|
||||||
|
char buf[MAXSTR];
|
||||||
|
|
||||||
|
if (ph.notify != NULL)
|
||||||
|
{
|
||||||
|
inslen = ph.notify(ph.assemble, ea, cs, ip, use32, line, buf);
|
||||||
|
if (inslen > 0)
|
||||||
|
{
|
||||||
|
patch_many_bytes(ea, buf, inslen);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
/*
|
/*
|
||||||
#<pydoc>
|
#<pydoc>
|
||||||
@ -408,6 +375,7 @@ static PyObject *ph_get_regnames()
|
|||||||
PyObject *py_result = PyList_New(ph.regsNum);
|
PyObject *py_result = PyList_New(ph.regsNum);
|
||||||
for ( Py_ssize_t i=0; i<ph.regsNum; i++ )
|
for ( Py_ssize_t i=0; i<ph.regsNum; i++ )
|
||||||
PyList_SetItem(py_result, i, PyString_FromString(ph.regNames[i]));
|
PyList_SetItem(py_result, i, PyString_FromString(ph.regNames[i]));
|
||||||
|
|
||||||
return py_result;
|
return py_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,6 +383,21 @@ static PyObject *ph_get_regnames()
|
|||||||
/*
|
/*
|
||||||
#<pydoc>
|
#<pydoc>
|
||||||
class IDP_Hooks(object):
|
class IDP_Hooks(object):
|
||||||
|
def hook(self):
|
||||||
|
"""
|
||||||
|
Creates an IDP hook
|
||||||
|
|
||||||
|
@return: Boolean true on success
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def unhook(self):
|
||||||
|
"""
|
||||||
|
Removes the IDP hook
|
||||||
|
@return: Boolean true on success
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
def custom_ana(self):
|
def custom_ana(self):
|
||||||
"""
|
"""
|
||||||
Analyzes and decodes an instruction at idaapi.cmd.ea
|
Analyzes and decodes an instruction at idaapi.cmd.ea
|
||||||
@ -480,9 +463,9 @@ class IDP_Hooks(object):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def is_sane_insn(self, no_crefs):
|
def may_be_func(self, no_crefs):
|
||||||
"""
|
"""
|
||||||
can a function start here?
|
Can a function start here?
|
||||||
@param state: autoanalysis phase
|
@param state: autoanalysis phase
|
||||||
0: creating functions
|
0: creating functions
|
||||||
1: creating chunks
|
1: creating chunks
|
||||||
@ -490,8 +473,124 @@ class IDP_Hooks(object):
|
|||||||
@return: integer (probability 0..100)
|
@return: integer (probability 0..100)
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def closebase(self):
|
||||||
|
"""
|
||||||
|
The database will be closed now
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def savebase(self):
|
||||||
|
"""
|
||||||
|
The database is being saved. Processor module should
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def rename(self, ea, new_name):
|
||||||
|
"""
|
||||||
|
The kernel is going to rename a byte.
|
||||||
|
|
||||||
|
@param ea: Address
|
||||||
|
@param new_name: The new name
|
||||||
|
|
||||||
|
@return:
|
||||||
|
- If returns value <=0, then the kernel should
|
||||||
|
not rename it. See also the 'renamed' event
|
||||||
|
"""
|
||||||
|
|
||||||
|
def renamed(self, ea, new_name, local_name):
|
||||||
|
"""
|
||||||
|
The kernel has renamed a byte
|
||||||
|
|
||||||
|
@param ea: Address
|
||||||
|
@param new_name: The new name
|
||||||
|
@param local_name: Is local name
|
||||||
|
|
||||||
|
@return: Ignored
|
||||||
|
"""
|
||||||
|
|
||||||
|
def undefine(self, ea):
|
||||||
|
"""
|
||||||
|
An item in the database (insn or data) is being deleted
|
||||||
|
@param ea: Address
|
||||||
|
@return:
|
||||||
|
- returns: >0-ok, <=0-the kernel should stop
|
||||||
|
- if the return value is positive:
|
||||||
|
bit0 - ignored
|
||||||
|
bit1 - do not delete srareas at the item end
|
||||||
|
"""
|
||||||
|
|
||||||
|
def make_code(self, ea, size):
|
||||||
|
"""
|
||||||
|
An instruction is being created
|
||||||
|
@param ea: Address
|
||||||
|
@param size: Instruction size
|
||||||
|
@return: 1-ok, <=0-the kernel should stop
|
||||||
|
"""
|
||||||
|
|
||||||
|
def make_code(self, ea, size):
|
||||||
|
"""
|
||||||
|
An instruction is being created
|
||||||
|
@param ea: Address
|
||||||
|
@param size: Instruction size
|
||||||
|
@return: 1-ok, <=0-the kernel should stop
|
||||||
|
"""
|
||||||
|
|
||||||
|
def make_data(self, ea, flags, tid, len):
|
||||||
|
"""
|
||||||
|
A data item is being created
|
||||||
|
@param ea: Address
|
||||||
|
@param tid: type id
|
||||||
|
@param flags: item flags
|
||||||
|
@param len: data item size
|
||||||
|
@return: 1-ok, <=0-the kernel should stop
|
||||||
|
"""
|
||||||
|
|
||||||
|
def load_idasgn(self, short_sig_name):
|
||||||
|
"""
|
||||||
|
FLIRT signature have been loaded for normal processing
|
||||||
|
(not for recognition of startup sequences)
|
||||||
|
@param short_sig_name: signature name
|
||||||
|
@return: Ignored
|
||||||
|
"""
|
||||||
|
|
||||||
|
def add_func(self, func):
|
||||||
|
"""
|
||||||
|
The kernel has added a function
|
||||||
|
@param func: the func_t instance
|
||||||
|
@return: Ignored
|
||||||
|
"""
|
||||||
|
|
||||||
|
def del_func(self, func):
|
||||||
|
"""
|
||||||
|
The kernel is about to delete a function
|
||||||
|
@param func: the func_t instance
|
||||||
|
@return: 1-ok,<=0-do not delete
|
||||||
|
"""
|
||||||
|
|
||||||
|
def is_call_insn(self, ea, func_name):
|
||||||
|
"""
|
||||||
|
Is the instruction a "call"?
|
||||||
|
|
||||||
|
@param ea: instruction address
|
||||||
|
@return: 1-unknown, 0-no, 2-yes
|
||||||
|
"""
|
||||||
|
|
||||||
|
def is_ret_insn(self, ea, func_name):
|
||||||
|
"""
|
||||||
|
Is the instruction a "return"?
|
||||||
|
|
||||||
|
@param ea: instruction address
|
||||||
|
@param strict: - True: report only ret instructions
|
||||||
|
False: include instructions like "leave" which begins the function epilog
|
||||||
|
@return: 1-unknown, 0-no, 2-yes
|
||||||
|
"""
|
||||||
|
|
||||||
#</pydoc>
|
#</pydoc>
|
||||||
*/
|
*/
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// IDP hooks
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
int idaapi IDP_Callback(void *ud, int notification_code, va_list va);
|
int idaapi IDP_Callback(void *ud, int notification_code, va_list va);
|
||||||
class IDP_Hooks
|
class IDP_Hooks
|
||||||
{
|
{
|
||||||
@ -544,12 +643,287 @@ public:
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual int closebase()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void savebase()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int rename(ea_t ea, const char *new_name)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void renamed(ea_t ea, const char *new_name, bool local_name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int undefine(ea_t ea)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int make_code(ea_t ea, asize_t size)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int make_data(ea_t ea, flags_t flags, tid_t tid, asize_t len)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void load_idasgn(const char *short_sig_name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void add_func(func_t *func)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int del_func(func_t *func)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int is_call_insn(ea_t ea)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int is_ret_insn(ea_t ea, bool strict)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// IDB hooks
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
int idaapi IDB_Callback(void *ud, int notification_code, va_list va);
|
||||||
|
class IDB_Hooks
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~IDB_Hooks() {};
|
||||||
|
|
||||||
|
bool hook()
|
||||||
|
{
|
||||||
|
return hook_to_notification_point(HT_IDB, IDB_Callback, this);
|
||||||
|
}
|
||||||
|
bool unhook()
|
||||||
|
{
|
||||||
|
return unhook_from_notification_point(HT_IDB, IDB_Callback, this);
|
||||||
|
}
|
||||||
|
// Hook functions to override in Python
|
||||||
|
virtual int byte_patched(ea_t ea) { return 0; };
|
||||||
|
virtual int cmt_changed(ea_t, bool repeatable_cmt) { return 0; };
|
||||||
|
virtual int ti_changed(ea_t ea, const type_t *type, const p_list *fnames) { msg("ti_changed hook not supported yet\n"); return 0; };
|
||||||
|
virtual int op_ti_changed(ea_t ea, int n, const type_t *type, const p_list *fnames) { msg("op_ti_changed hook not supported yet\n"); return 0; };
|
||||||
|
virtual int op_type_changed(ea_t ea, int n) { return 0; };
|
||||||
|
virtual int enum_created(enum_t id) { return 0; };
|
||||||
|
virtual int enum_deleted(enum_t id) { return 0; };
|
||||||
|
virtual int enum_bf_changed(enum_t id) { return 0; };
|
||||||
|
virtual int enum_renamed(enum_t id) { return 0; };
|
||||||
|
virtual int enum_cmt_changed(enum_t id) { return 0; };
|
||||||
|
virtual int enum_member_created(enum_t id, const_t cid) { return 0; };
|
||||||
|
virtual int enum_member_deleted(enum_t id, const_t cid) { return 0; };
|
||||||
|
virtual int struc_created(tid_t struc_id) { return 0; };
|
||||||
|
virtual int struc_deleted(tid_t struc_id) { return 0; };
|
||||||
|
virtual int struc_renamed(struc_t *sptr) { return 0; };
|
||||||
|
virtual int struc_expanded(struc_t *sptr) { return 0; };
|
||||||
|
virtual int struc_cmt_changed(tid_t struc_id) { return 0; };
|
||||||
|
virtual int struc_member_created(struc_t *sptr, member_t *mptr) { return 0; };
|
||||||
|
virtual int struc_member_deleted(struc_t *sptr, tid_t member_id) { return 0; };
|
||||||
|
virtual int struc_member_renamed(struc_t *sptr, member_t *mptr) { return 0; };
|
||||||
|
virtual int struc_member_changed(struc_t *sptr, member_t *mptr) { return 0; };
|
||||||
|
virtual int thunk_func_created(func_t *pfn) { return 0; };
|
||||||
|
virtual int func_tail_appended(func_t *pfn, func_t *tail) { return 0; };
|
||||||
|
virtual int func_tail_removed(func_t *pfn, ea_t tail_ea) { return 0; };
|
||||||
|
virtual int tail_owner_changed(func_t *tail, ea_t owner_func) { return 0; };
|
||||||
|
virtual int func_noret_changed(func_t *pfn) { return 0; };
|
||||||
|
virtual int segm_added(segment_t *s) { return 0; };
|
||||||
|
virtual int segm_deleted(ea_t startEA) { return 0; };
|
||||||
|
virtual int segm_start_changed(segment_t *s) { return 0; };
|
||||||
|
virtual int segm_end_changed(segment_t *s) { return 0; };
|
||||||
|
virtual int segm_moved(ea_t from, ea_t to, asize_t size) { return 0; };
|
||||||
};
|
};
|
||||||
|
|
||||||
//</inline(py_idp)>
|
//</inline(py_idp)>
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
//<code(py_idp)>
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
int idaapi IDP_Callback(void *ud, int notification_code, va_list va)
|
||||||
|
{
|
||||||
|
IDP_Hooks *proxy = (IDP_Hooks *)ud;
|
||||||
|
int ret = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
switch ( notification_code )
|
||||||
|
{
|
||||||
|
case processor_t::custom_ana:
|
||||||
|
ret = proxy->custom_ana() ? 1 + cmd.size : 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case processor_t::custom_out:
|
||||||
|
ret = proxy->custom_out() ? 2 : 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case processor_t::custom_emu:
|
||||||
|
ret = proxy->custom_emu() ? 2 : 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case processor_t::custom_outop:
|
||||||
|
{
|
||||||
|
op_t *op = va_arg(va, op_t *);
|
||||||
|
PyObject *py_obj = create_idaapi_linked_class_instance(S_PY_OP_T_CLSNAME, op);
|
||||||
|
if ( py_obj == NULL )
|
||||||
|
break;
|
||||||
|
ret = proxy->custom_outop(py_obj) ? 2 : 0;
|
||||||
|
Py_XDECREF(py_obj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case processor_t::custom_mnem:
|
||||||
|
{
|
||||||
|
PyObject *py_ret = proxy->custom_mnem();
|
||||||
|
if ( py_ret != NULL && PyString_Check(py_ret) )
|
||||||
|
{
|
||||||
|
char *outbuffer = va_arg(va, char *);
|
||||||
|
size_t bufsize = va_arg(va, size_t);
|
||||||
|
|
||||||
|
qstrncpy(outbuffer, PyString_AS_STRING(py_ret), bufsize);
|
||||||
|
ret = 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
Py_XDECREF(py_ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case processor_t::is_sane_insn:
|
||||||
|
{
|
||||||
|
int no_crefs = va_arg(va, int);
|
||||||
|
ret = proxy->is_sane_insn(no_crefs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case processor_t::may_be_func:
|
||||||
|
{
|
||||||
|
int state = va_arg(va, int);
|
||||||
|
ret = proxy->may_be_func(state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case processor_t::closebase:
|
||||||
|
{
|
||||||
|
proxy->closebase();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case processor_t::savebase:
|
||||||
|
{
|
||||||
|
proxy->savebase();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case processor_t::rename:
|
||||||
|
{
|
||||||
|
ea_t ea = va_arg(va, ea_t);
|
||||||
|
const char *new_name = va_arg(va, const char *);
|
||||||
|
ret = proxy->rename(ea, new_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case processor_t::renamed:
|
||||||
|
{
|
||||||
|
ea_t ea = va_arg(va, ea_t);
|
||||||
|
const char *new_name = va_arg(va, const char *);
|
||||||
|
bool local_name = va_argi(va, bool);
|
||||||
|
proxy->renamed(ea, new_name, local_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case processor_t::undefine:
|
||||||
|
{
|
||||||
|
ea_t ea = va_arg(va, ea_t);
|
||||||
|
ret = proxy->undefine(ea);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case processor_t::make_code:
|
||||||
|
{
|
||||||
|
ea_t ea = va_arg(va, ea_t);
|
||||||
|
asize_t size = va_arg(va, asize_t);
|
||||||
|
ret = proxy->make_code(ea, size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case processor_t::make_data:
|
||||||
|
{
|
||||||
|
ea_t ea = va_arg(va, ea_t);
|
||||||
|
flags_t flags = va_arg(va, flags_t);
|
||||||
|
tid_t tid = va_arg(va, tid_t);
|
||||||
|
asize_t len = va_arg(va, asize_t);
|
||||||
|
ret = proxy->make_data(ea, flags, tid, len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case processor_t::load_idasgn:
|
||||||
|
{
|
||||||
|
const char *short_sig_name = va_arg(va, const char *);
|
||||||
|
proxy->load_idasgn(short_sig_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case processor_t::add_func:
|
||||||
|
{
|
||||||
|
func_t *func = va_arg(va, func_t *);
|
||||||
|
proxy->add_func(func);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case processor_t::del_func:
|
||||||
|
{
|
||||||
|
func_t *func = va_arg(va, func_t *);
|
||||||
|
ret = proxy->del_func(func);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case processor_t::is_call_insn:
|
||||||
|
{
|
||||||
|
ea_t ea = va_arg(va, ea_t);
|
||||||
|
ret = proxy->is_call_insn(ea);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case processor_t::is_ret_insn:
|
||||||
|
{
|
||||||
|
ea_t ea = va_arg(va, ea_t);
|
||||||
|
bool strict = va_argi(va, bool);
|
||||||
|
ret = proxy->is_ret_insn(ea, strict);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Swig::DirectorException &)
|
||||||
|
{
|
||||||
|
msg("Exception in IDP Hook function:\n");
|
||||||
|
if ( PyErr_Occurred() )
|
||||||
|
PyErr_Print();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
|
int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
|
||||||
{
|
{
|
||||||
class IDB_Hooks *proxy = (class IDB_Hooks *)ud;
|
class IDB_Hooks *proxy = (class IDB_Hooks *)ud;
|
||||||
@ -615,12 +989,20 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
|
|||||||
id = va_arg(va, enum_t);
|
id = va_arg(va, enum_t);
|
||||||
return proxy->enum_cmt_changed(id);
|
return proxy->enum_cmt_changed(id);
|
||||||
|
|
||||||
|
#ifdef NO_OBSOLETE_FUNCS
|
||||||
case idb_event::enum_member_created:
|
case idb_event::enum_member_created:
|
||||||
|
#else
|
||||||
|
case idb_event::enum_const_created:
|
||||||
|
#endif
|
||||||
id = va_arg(va, enum_t);
|
id = va_arg(va, enum_t);
|
||||||
cid = va_arg(va, const_t);
|
cid = va_arg(va, const_t);
|
||||||
return proxy->enum_member_created(id, cid);
|
return proxy->enum_member_created(id, cid);
|
||||||
|
|
||||||
|
#ifdef NO_OBSOLETE_FUNCS
|
||||||
case idb_event::enum_member_deleted:
|
case idb_event::enum_member_deleted:
|
||||||
|
#else
|
||||||
|
case idb_event::enum_const_deleted:
|
||||||
|
#endif
|
||||||
id = va_arg(va, enum_t);
|
id = va_arg(va, enum_t);
|
||||||
cid = va_arg(va, const_t);
|
cid = va_arg(va, const_t);
|
||||||
return proxy->enum_member_deleted(id, cid);
|
return proxy->enum_member_deleted(id, cid);
|
||||||
@ -722,86 +1104,6 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//<code(py_idp)>
|
|
||||||
//-------------------------------------------------------------------------
|
|
||||||
int idaapi IDP_Callback(void *ud, int notification_code, va_list va)
|
|
||||||
{
|
|
||||||
IDP_Hooks *proxy = (IDP_Hooks *)ud;
|
|
||||||
int ret;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
switch ( notification_code )
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
ret = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case processor_t::custom_ana:
|
|
||||||
ret = proxy->custom_ana() ? 1 + cmd.size : 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case processor_t::custom_out:
|
|
||||||
ret = proxy->custom_out() ? 2 : 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case processor_t::custom_emu:
|
|
||||||
ret = proxy->custom_emu() ? 2 : 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case processor_t::custom_outop:
|
|
||||||
{
|
|
||||||
op_t *op = va_arg(va, op_t *);
|
|
||||||
PyObject *py_obj = create_idaapi_linked_class_instance(S_PY_OP_T_CLSNAME, op);
|
|
||||||
if ( py_obj == NULL )
|
|
||||||
break;
|
|
||||||
ret = proxy->custom_outop(py_obj) ? 2 : 0;
|
|
||||||
Py_XDECREF(py_obj);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case processor_t::custom_mnem:
|
|
||||||
{
|
|
||||||
PyObject *py_ret = proxy->custom_mnem();
|
|
||||||
if ( py_ret != NULL && PyString_Check(py_ret) )
|
|
||||||
{
|
|
||||||
char *outbuffer = va_arg(va, char *);
|
|
||||||
size_t bufsize = va_arg(va, size_t);
|
|
||||||
|
|
||||||
qstrncpy(outbuffer, PyString_AS_STRING(py_ret), bufsize);
|
|
||||||
ret = 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
Py_XDECREF(py_ret);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case processor_t::is_sane_insn:
|
|
||||||
{
|
|
||||||
int no_crefs = va_arg(va, int);
|
|
||||||
ret = proxy->is_sane_insn(no_crefs);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case processor_t::may_be_func:
|
|
||||||
{
|
|
||||||
int state = va_arg(va, int);
|
|
||||||
ret = proxy->may_be_func(state);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Swig::DirectorException &)
|
|
||||||
{
|
|
||||||
msg("Exception in IDP Hook function:\n");
|
|
||||||
if ( PyErr_Occurred() )
|
|
||||||
PyErr_Print();
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
//</code(py_idp)>
|
//</code(py_idp)>
|
||||||
%}
|
%}
|
3411
swig/kernwin.i
3411
swig/kernwin.i
File diff suppressed because it is too large
Load Diff
11
swig/lines.i
11
swig/lines.i
@ -78,7 +78,6 @@
|
|||||||
//<code(py_lines)>
|
//<code(py_lines)>
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
static PyObject *py_get_user_defined_prefix = NULL;
|
static PyObject *py_get_user_defined_prefix = NULL;
|
||||||
static qstring py_get_user_defined_prefix_err;
|
|
||||||
static void idaapi s_py_get_user_defined_prefix(
|
static void idaapi s_py_get_user_defined_prefix(
|
||||||
ea_t ea,
|
ea_t ea,
|
||||||
int lnnum,
|
int lnnum,
|
||||||
@ -92,12 +91,9 @@ static void idaapi s_py_get_user_defined_prefix(
|
|||||||
PY_FMT64 "iis" PY_FMT64,
|
PY_FMT64 "iis" PY_FMT64,
|
||||||
ea, lnnum, indent, line, bufsize);
|
ea, lnnum, indent, line, bufsize);
|
||||||
|
|
||||||
if ( PyW_GetError(&py_get_user_defined_prefix_err) || py_ret == NULL )
|
// Error? Display it
|
||||||
{
|
// No error? Copy the buffer
|
||||||
msg("py_get_user_defined_prefix() error: %s\n", py_get_user_defined_prefix_err.c_str());
|
if ( !PyW_ShowCbErr("py_get_user_defined_prefix") )
|
||||||
PyErr_Clear();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
Py_ssize_t py_len;
|
Py_ssize_t py_len;
|
||||||
char *py_str;
|
char *py_str;
|
||||||
@ -192,6 +188,7 @@ PyObject *py_tag_remove(const char *instr)
|
|||||||
char *buf = new char[sz + 5];
|
char *buf = new char[sz + 5];
|
||||||
if ( buf == NULL )
|
if ( buf == NULL )
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
ssize_t r = tag_remove(instr, buf, sz);
|
ssize_t r = tag_remove(instr, buf, sz);
|
||||||
PyObject *res;
|
PyObject *res;
|
||||||
if ( r < 0 )
|
if ( r < 0 )
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
// TODO: These could be wrapped if needed
|
// TODO: These could be wrapped if needed
|
||||||
%ignore load_info_t;
|
%ignore load_info_t;
|
||||||
%ignore add_plugin_option;
|
%ignore add_plugin_option;
|
||||||
|
%ignore get_plugins_path;
|
||||||
%ignore build_loaders_list;
|
%ignore build_loaders_list;
|
||||||
%ignore free_loaders_list;
|
%ignore free_loaders_list;
|
||||||
%ignore get_loader_name_from_dll;
|
%ignore get_loader_name_from_dll;
|
||||||
@ -147,6 +148,7 @@ static int py_mem2base(PyObject *py_mem, ea_t ea, long fpos = -1)
|
|||||||
char *buf;
|
char *buf;
|
||||||
if ( PyString_AsStringAndSize(py_mem, &buf, &len) == -1 )
|
if ( PyString_AsStringAndSize(py_mem, &buf, &len) == -1 )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return mem2base((void *)buf, ea, ea+len, fpos);
|
return mem2base((void *)buf, ea, ea+len, fpos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,6 +170,7 @@ static PyObject *py_load_plugin(const char *name)
|
|||||||
plugin_t *r = load_plugin(name);
|
plugin_t *r = load_plugin(name);
|
||||||
if ( r == NULL )
|
if ( r == NULL )
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
return PyCObject_FromVoidPtr(r, NULL);
|
return PyCObject_FromVoidPtr(r, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,6 +190,7 @@ static bool py_run_plugin(PyObject *plg, int arg)
|
|||||||
{
|
{
|
||||||
if ( !PyCObject_Check(plg) )
|
if ( !PyCObject_Check(plg) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return run_plugin((plugin_t *)PyCObject_AsVoidPtr(plg), arg);
|
return run_plugin((plugin_t *)PyCObject_AsVoidPtr(plg), arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
23
swig/nalt.i
23
swig/nalt.i
@ -25,7 +25,11 @@ static int idaapi py_import_enum_cb(
|
|||||||
uval_t ord,
|
uval_t ord,
|
||||||
void *param)
|
void *param)
|
||||||
{
|
{
|
||||||
PyObject *py_ea = Py_BuildValue(PY_FMT64, pyul_t(ea));
|
// If no name, try to get the name associated with the 'ea'. It may be coming from IDS
|
||||||
|
char name_buf[MAXSTR];
|
||||||
|
if ( name == NULL )
|
||||||
|
name = get_true_name(BADADDR, ea, name_buf, sizeof(name_buf));
|
||||||
|
|
||||||
PyObject *py_name;
|
PyObject *py_name;
|
||||||
if ( name == NULL )
|
if ( name == NULL )
|
||||||
{
|
{
|
||||||
@ -36,13 +40,25 @@ static int idaapi py_import_enum_cb(
|
|||||||
{
|
{
|
||||||
py_name = PyString_FromString(name);
|
py_name = PyString_FromString(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *py_ord = Py_BuildValue(PY_FMT64, pyul_t(ord));
|
PyObject *py_ord = Py_BuildValue(PY_FMT64, pyul_t(ord));
|
||||||
PyObject *py_result = PyObject_CallFunctionObjArgs((PyObject *)param, py_ea, py_name, py_ord, NULL);
|
PyObject *py_ea = Py_BuildValue(PY_FMT64, pyul_t(ea));
|
||||||
|
PYW_GIL_ENSURE;
|
||||||
|
PyObject *py_result = PyObject_CallFunctionObjArgs(
|
||||||
|
(PyObject *)param,
|
||||||
|
py_ea,
|
||||||
|
py_name,
|
||||||
|
py_ord,
|
||||||
|
NULL);
|
||||||
|
PYW_GIL_RELEASE;
|
||||||
|
|
||||||
int r = py_result != NULL && PyObject_IsTrue(py_result) ? 1 : 0;
|
int r = py_result != NULL && PyObject_IsTrue(py_result) ? 1 : 0;
|
||||||
|
|
||||||
Py_DECREF(py_ea);
|
Py_DECREF(py_ea);
|
||||||
Py_DECREF(py_name);
|
Py_DECREF(py_name);
|
||||||
Py_DECREF(py_ord);
|
Py_DECREF(py_ord);
|
||||||
Py_XDECREF(py_result);
|
Py_XDECREF(py_result);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,6 +106,7 @@ static PyObject *py_get_import_module_name(int mod_index)
|
|||||||
char buf[MAXSTR];
|
char buf[MAXSTR];
|
||||||
if ( !get_import_module_name(mod_index, buf, sizeof(buf)) )
|
if ( !get_import_module_name(mod_index, buf, sizeof(buf)) )
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
return PyString_FromString(buf);
|
return PyString_FromString(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,6 +251,7 @@ static int py_enum_import_names(int mod_index, PyObject *py_cb)
|
|||||||
{
|
{
|
||||||
if ( !PyCallable_Check(py_cb) )
|
if ( !PyCallable_Check(py_cb) )
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return enum_import_names(mod_index, py_import_enum_cb, py_cb);
|
return enum_import_names(mod_index, py_import_enum_cb, py_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,6 +262,7 @@ static PyObject *switch_info_ex_t_create()
|
|||||||
return PyCObject_FromVoidPtr(inst, NULL);
|
return PyCObject_FromVoidPtr(inst, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
static bool switch_info_ex_t_destroy(PyObject *py_obj)
|
static bool switch_info_ex_t_destroy(PyObject *py_obj)
|
||||||
{
|
{
|
||||||
if ( !PyCObject_Check(py_obj) )
|
if ( !PyCObject_Check(py_obj) )
|
||||||
|
18
swig/name.i
18
swig/name.i
@ -45,7 +45,7 @@ PyObject *py_get_debug_names(ea_t ea1, ea_t ea2)
|
|||||||
for (ea_name_vec_t::iterator it=names.begin();it!=names.end();++it)
|
for (ea_name_vec_t::iterator it=names.begin();it!=names.end();++it)
|
||||||
{
|
{
|
||||||
PyDict_SetItem(dict,
|
PyDict_SetItem(dict,
|
||||||
PyInt_FromSize_t(it->ea),
|
Py_BuildValue(PY_FMT64, it->ea),
|
||||||
PyString_FromString(it->name.c_str()));
|
PyString_FromString(it->name.c_str()));
|
||||||
}
|
}
|
||||||
return dict;
|
return dict;
|
||||||
@ -63,12 +63,14 @@ class NearestName:
|
|||||||
def __init__(self, ea_names):
|
def __init__(self, ea_names):
|
||||||
self.update(ea_names)
|
self.update(ea_names)
|
||||||
|
|
||||||
|
|
||||||
def update(self, ea_names):
|
def update(self, ea_names):
|
||||||
"""Updates the ea/names map"""
|
"""Updates the ea/names map"""
|
||||||
self._names = ea_names
|
self._names = ea_names
|
||||||
self._addrs = ea_names.keys()
|
self._addrs = ea_names.keys()
|
||||||
self._addrs.sort()
|
self._addrs.sort()
|
||||||
|
|
||||||
|
|
||||||
def find(self, ea):
|
def find(self, ea):
|
||||||
"""
|
"""
|
||||||
Returns a tupple (ea, name, pos) that is the nearest to the passed ea
|
Returns a tupple (ea, name, pos) that is the nearest to the passed ea
|
||||||
@ -85,13 +87,21 @@ class NearestName:
|
|||||||
return None
|
return None
|
||||||
return self[pos]
|
return self[pos]
|
||||||
|
|
||||||
|
|
||||||
|
def _get_item(self, index):
|
||||||
|
ea = self._addrs[index]
|
||||||
|
return (ea, self._names[ea], index)
|
||||||
|
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return (self._get_item(index) for index in xrange(0, len(self._addrs)))
|
||||||
|
|
||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, index):
|
||||||
"""Returns the tupple (ea, name, index)"""
|
"""Returns the tupple (ea, name, index)"""
|
||||||
if index > len(self._addrs):
|
if index > len(self._addrs):
|
||||||
raise StopIteration
|
raise StopIteration
|
||||||
ea = self._addrs[index]
|
return self._get_item(index)
|
||||||
return (ea, self._names[ea], index)
|
|
||||||
|
|
||||||
%}
|
%}
|
||||||
%include "name.hpp"
|
%include "name.hpp"
|
||||||
|
|
||||||
|
@ -89,3 +89,11 @@
|
|||||||
%rename (hashset_idx) netnode::hashset(const char *idx, nodeidx_t value, char tag=htag);
|
%rename (hashset_idx) netnode::hashset(const char *idx, nodeidx_t value, char tag=htag);
|
||||||
|
|
||||||
%include "netnode.hpp"
|
%include "netnode.hpp"
|
||||||
|
|
||||||
|
%extend netnode
|
||||||
|
{
|
||||||
|
nodeidx_t index()
|
||||||
|
{
|
||||||
|
return self->operator nodeidx_t();
|
||||||
|
}
|
||||||
|
}
|
14
swig/pro.i
14
swig/pro.i
@ -23,7 +23,14 @@
|
|||||||
%ignore qthread_join;
|
%ignore qthread_join;
|
||||||
%ignore qthread_kill;
|
%ignore qthread_kill;
|
||||||
%ignore qthread_self;
|
%ignore qthread_self;
|
||||||
|
%ignore qthread_same;
|
||||||
%ignore qthread_t;
|
%ignore qthread_t;
|
||||||
|
%ignore qhandle_t;
|
||||||
|
%ignore qpipe_create;
|
||||||
|
%ignore qpipe_read;
|
||||||
|
%ignore qpipe_write;
|
||||||
|
%ignore qpipe_close;
|
||||||
|
%ignore qwait_for_handles;
|
||||||
%ignore qstrlen;
|
%ignore qstrlen;
|
||||||
%ignore qstrcmp;
|
%ignore qstrcmp;
|
||||||
%ignore qstrstr;
|
%ignore qstrstr;
|
||||||
@ -65,8 +72,11 @@
|
|||||||
%ignore swap_value;
|
%ignore swap_value;
|
||||||
%ignore qalloc_or_throw;
|
%ignore qalloc_or_throw;
|
||||||
%ignore qrealloc_or_throw;
|
%ignore qrealloc_or_throw;
|
||||||
%ignore launch_process_t;
|
%ignore get_buffer_for_sysdir;
|
||||||
%ignore init_process;
|
%ignore get_buffer_for_winerr;
|
||||||
|
%ignore call_atexits;
|
||||||
|
%ignore launch_process_params_t;
|
||||||
|
%ignore launch_process;
|
||||||
%ignore term_process;
|
%ignore term_process;
|
||||||
%ignore get_process_exit_code;
|
%ignore get_process_exit_code;
|
||||||
%ignore BELOW_NORMAL_PRIORITY_CLASS;
|
%ignore BELOW_NORMAL_PRIORITY_CLASS;
|
||||||
|
@ -148,8 +148,20 @@
|
|||||||
// Check that the argument is a callable Python object
|
// Check that the argument is a callable Python object
|
||||||
%typemap(in) PyObject *pyfunc {
|
%typemap(in) PyObject *pyfunc {
|
||||||
if (!PyCallable_Check($input)) {
|
if (!PyCallable_Check($input)) {
|
||||||
PyErr_SetString(PyExc_TypeError, "Expecting a callable object");
|
PyErr_SetString(PyExc_TypeError, "Expected a callable object");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
$1 = $input;
|
$1 = $input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert ea_t
|
||||||
|
%typemap(in) ea_t
|
||||||
|
{
|
||||||
|
uint64 $1_temp;
|
||||||
|
if ( !PyW_GetNumber($input, &$1_temp) )
|
||||||
|
{
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Expected an ea_t type");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
$1 = ea_t($1_temp);
|
||||||
|
}
|
||||||
|
@ -62,6 +62,9 @@
|
|||||||
%ignore print_type;
|
%ignore print_type;
|
||||||
%ignore show_type;
|
%ignore show_type;
|
||||||
%ignore show_plist;
|
%ignore show_plist;
|
||||||
|
%ignore skip_function_arg_names;
|
||||||
|
%ignore perform_funcarg_conversion;
|
||||||
|
%ignore get_argloc_info;
|
||||||
|
|
||||||
%ignore extract_pstr;
|
%ignore extract_pstr;
|
||||||
%ignore extract_name;
|
%ignore extract_name;
|
||||||
@ -167,6 +170,7 @@ PyObject *idc_parse_decl(til_t *ti, const char *decl, int flags)
|
|||||||
bool ok = parse_decl(ti, decl, &name, &type, &fields, flags);
|
bool ok = parse_decl(ti, decl, &name, &type, &fields, flags);
|
||||||
if ( !ok )
|
if ( !ok )
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
return Py_BuildValue("(sss)",
|
return Py_BuildValue("(sss)",
|
||||||
name.c_str(),
|
name.c_str(),
|
||||||
(char *)type.c_str(),
|
(char *)type.c_str(),
|
||||||
@ -256,7 +260,14 @@ PyObject *py_unpack_object_from_idb(
|
|||||||
type_t *type = (type_t *) PyString_AsString(py_type);
|
type_t *type = (type_t *) PyString_AsString(py_type);
|
||||||
p_list *fields = (p_list *) PyString_AsString(py_fields);
|
p_list *fields = (p_list *) PyString_AsString(py_fields);
|
||||||
idc_value_t idc_obj;
|
idc_value_t idc_obj;
|
||||||
error_t err = unpack_object_from_idb(&idc_obj, ti, type, fields, ea, NULL, pio_flags);
|
error_t err = unpack_object_from_idb(
|
||||||
|
&idc_obj,
|
||||||
|
ti,
|
||||||
|
type,
|
||||||
|
fields,
|
||||||
|
ea,
|
||||||
|
NULL,
|
||||||
|
pio_flags);
|
||||||
|
|
||||||
// Unpacking failed?
|
// Unpacking failed?
|
||||||
if ( err != eOk )
|
if ( err != eOk )
|
||||||
@ -265,9 +276,11 @@ PyObject *py_unpack_object_from_idb(
|
|||||||
// Convert
|
// Convert
|
||||||
PyObject *py_ret(NULL);
|
PyObject *py_ret(NULL);
|
||||||
err = idcvar_to_pyvar(idc_obj, &py_ret);
|
err = idcvar_to_pyvar(idc_obj, &py_ret);
|
||||||
|
|
||||||
// Conversion failed?
|
// Conversion failed?
|
||||||
if ( err != CIP_OK )
|
if ( err != CIP_OK )
|
||||||
return Py_BuildValue("(ii)", 0, err);
|
return Py_BuildValue("(ii)", 0, err);
|
||||||
|
|
||||||
PyObject *py_result = Py_BuildValue("(iO)", 1, py_ret);
|
PyObject *py_result = Py_BuildValue("(iO)", 1, py_ret);
|
||||||
Py_DECREF(py_ret);
|
Py_DECREF(py_ret);
|
||||||
return py_result;
|
return py_result;
|
||||||
@ -315,7 +328,13 @@ PyObject *py_unpack_object_from_bv(
|
|||||||
memcpy(bytes.begin(), PyString_AsString(py_bytes), bytes.size());
|
memcpy(bytes.begin(), PyString_AsString(py_bytes), bytes.size());
|
||||||
|
|
||||||
idc_value_t idc_obj;
|
idc_value_t idc_obj;
|
||||||
error_t err = unpack_object_from_bv(&idc_obj, ti, type, fields, bytes, pio_flags);
|
error_t err = unpack_object_from_bv(
|
||||||
|
&idc_obj,
|
||||||
|
ti,
|
||||||
|
type,
|
||||||
|
fields,
|
||||||
|
bytes,
|
||||||
|
pio_flags);
|
||||||
|
|
||||||
// Unpacking failed?
|
// Unpacking failed?
|
||||||
if ( err != eOk )
|
if ( err != eOk )
|
||||||
@ -324,9 +343,11 @@ PyObject *py_unpack_object_from_bv(
|
|||||||
// Convert
|
// Convert
|
||||||
PyObject *py_ret(NULL);
|
PyObject *py_ret(NULL);
|
||||||
err = idcvar_to_pyvar(idc_obj, &py_ret);
|
err = idcvar_to_pyvar(idc_obj, &py_ret);
|
||||||
|
|
||||||
// Conversion failed?
|
// Conversion failed?
|
||||||
if ( err != CIP_OK )
|
if ( err != CIP_OK )
|
||||||
return Py_BuildValue("(ii)", 0, err);
|
return Py_BuildValue("(ii)", 0, err);
|
||||||
|
|
||||||
PyObject *py_result = Py_BuildValue("(iO)", 1, py_ret);
|
PyObject *py_result = Py_BuildValue("(iO)", 1, py_ret);
|
||||||
Py_DECREF(py_ret);
|
Py_DECREF(py_ret);
|
||||||
return py_result;
|
return py_result;
|
||||||
|
14
swig/ua.i
14
swig/ua.i
@ -64,6 +64,7 @@ PyObject *py_init_output_buffer(size_t size = MAXSTR)
|
|||||||
PyObject *py_str = PyString_FromStringAndSize(NULL, size);
|
PyObject *py_str = PyString_FromStringAndSize(NULL, size);
|
||||||
if ( py_str == NULL )
|
if ( py_str == NULL )
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
init_output_buffer(PyString_AsString(py_str), size);
|
init_output_buffer(PyString_AsString(py_str), size);
|
||||||
return py_str;
|
return py_str;
|
||||||
}
|
}
|
||||||
@ -326,6 +327,7 @@ bool py_out_name_expr(
|
|||||||
off = adiff_t(v);
|
off = adiff_t(v);
|
||||||
else
|
else
|
||||||
off = BADADDR;
|
off = BADADDR;
|
||||||
|
|
||||||
return op == NULL ? false : out_name_expr(*op, ea, off);
|
return op == NULL ? false : out_name_expr(*op, ea, off);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,6 +451,7 @@ static void insn_t_set_cs(PyObject *self, PyObject *value)
|
|||||||
insn_t *link = insn_t_get_clink(self);
|
insn_t *link = insn_t_get_clink(self);
|
||||||
if ( link == NULL )
|
if ( link == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint64 v(0);
|
uint64 v(0);
|
||||||
PyW_GetNumber(value, &v);
|
PyW_GetNumber(value, &v);
|
||||||
link->cs = ea_t(v);
|
link->cs = ea_t(v);
|
||||||
@ -886,7 +889,7 @@ class op_t(py_clinked_object_t):
|
|||||||
|
|
||||||
def is_reg(self, r):
|
def is_reg(self, r):
|
||||||
"""Checks if the register operand is the given processor register"""
|
"""Checks if the register operand is the given processor register"""
|
||||||
return self.type == idaapi.o_reg and self == r
|
return self.type == _idaapi.o_reg and self == r
|
||||||
|
|
||||||
def has_reg(self, r):
|
def has_reg(self, r):
|
||||||
"""Checks if the operand accesses the given processor register"""
|
"""Checks if the operand accesses the given processor register"""
|
||||||
@ -1000,14 +1003,23 @@ class insn_t(py_clinked_object_t):
|
|||||||
def _create_clink(self):
|
def _create_clink(self):
|
||||||
return _idaapi.insn_t_create()
|
return _idaapi.insn_t_create()
|
||||||
|
|
||||||
|
|
||||||
def _del_clink(self, lnk):
|
def _del_clink(self, lnk):
|
||||||
return _idaapi.insn_t_destroy(lnk)
|
return _idaapi.insn_t_destroy(lnk)
|
||||||
|
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return (self.Operands[idx] for idx in xrange(0, UA_MAXOP))
|
||||||
|
|
||||||
|
|
||||||
def __getitem__(self, idx):
|
def __getitem__(self, idx):
|
||||||
"""
|
"""
|
||||||
Operands can be accessed directly as indexes
|
Operands can be accessed directly as indexes
|
||||||
@return op_t: Returns an operand of type op_t
|
@return op_t: Returns an operand of type op_t
|
||||||
"""
|
"""
|
||||||
|
if idx >= UA_MAXOP:
|
||||||
|
raise KeyError
|
||||||
|
else:
|
||||||
return self.Operands[idx]
|
return self.Operands[idx]
|
||||||
|
|
||||||
def is_macro(self):
|
def is_macro(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user