commit 9b85915a484afa37b940ee51c3ec057f54ab1dad Author: gergely.erdelyi Date: Sat Oct 20 07:03:51 2007 +0000 Initial SVN commit of version 0.9.54 sources. diff --git a/BUILDING.txt b/BUILDING.txt new file mode 100644 index 0000000..9f6e5a3 --- /dev/null +++ b/BUILDING.txt @@ -0,0 +1,63 @@ +---------------------------------------------------------- +IDAPython - Python plugin for Interactive Disassembler Pro +---------------------------------------------------------- +Building From Source +-------------------- + +REQUIREMENTS + +[Tested versions are in brackets] + + - IDA and IDA SDK [5.1] + http://www.datarescue.com/idabase/ + + - Python [2.4.4, 2.5] + http://www.python.org/ + + - Simplified Wrapper Interface Generator (SWIG) [1.3.31] + SWIG is not needed for regular building, only if you want to tweak the wrappers. + http://www.swig.org/ + + - Unix utilities (GNU patch on Windows): + http://www.research.att.com/sw/tools/uwin/ or + http://unxutils.sourceforge.net/ or + http://www.cygwin.com/ + + - GCC on Linux and Mac OS X [4.0] + Comes with your distribution + + - Microsoft Visual C on Windows [Microsoft Visual C++ 2005 Express Edition] + http://msdn.microsoft.com/vstudio/express/visualc/ + + +BUILDING + +Make sure all the needed tools (compiler, make, swig, etc) are on the +PATH. + +1, Unpack the IDAPython source and IDA Pro SDK into the following + directory structure: + + swigsdk-versions/5.1/ - version 5.0 of the IDA Pro SDK + idapython/ - IDAPython source code + +2, Patch the SDK using GNU Patch with one of patches from patches/ directory. + You will have to use the -P option depending on which directory you + patch from. + +2, Build the plugin + + python build.py + + It is possible to build the plugin for different Python versions by + running build.py with the corresponding Python binary. + +3, Install the components as described in README.txt + +See build.py for build details and tweak opportunities. + + +------------------------------------------------------------------------------- +Copyright (c) 2004-2007 Gergely Erdelyi . All rights reserved. +------------------------------------------------------------------------------- + diff --git a/CHANGES.txt b/CHANGES.txt new file mode 100644 index 0000000..58c134b --- /dev/null +++ b/CHANGES.txt @@ -0,0 +1,72 @@ +Changes from version 0.9.0 to 0.9.53 +------------------------------------ + +- Upgraded IDA Pro base version to 5.1 +- Experimental Mac OS X support +- Improved IDC coverage +- Cleanups and fixes + + +Changes from version 0.8.0 to 0.9.0 +----------------------------------- + +- Upgraded base version to IDA Pro 5.0 +- Works with IDA Pro 5.1 +- Python 2.4 and 2.5 supported +- Close to complete IDC compatbility layer (in sync with 4.9) +- Significatnly improved IDA SDK API covergage (see STATUS.txt for details) +- IDA SDK patch size reduced to less than half +- Simplified installation (plugins.cfg modification not needed) +- Evaluation window content is saved over IDA restarts (in the database) +- Windows version is built with Microsoft Visual C++ Express Edition +- Build makefile replaced with a Python script +- Cleanups and small fixes + + +Changes from version 0.7.0 to 0.8.0 +----------------------------------- + +- Added support for IDA Pro 4.9 +- Dropped support for IDA Pro 4.7 +- NOTE: Windows version is linked against Python 2.4. +- New wrappers: search.hpp, dbg.hpp, loader.hpp, diskio.hpp, nalt.hpp +- idc.py synced up to IDA 4.8 +- Added 38 IDC functions +- Fixed asklong(), askseg() and askaddr() +- Automatically generated cross reference documentation (epydoc) +- User-specific init file support (see README,txt) +- Deprecated some functions that have direct Python equivalents (see idc.py) +- Fixed exception in ScriptBox when invoked empty. +- Lots of cleanups and small fixes + + +Changes from version 0.6.0 to 0.7.0 +----------------------------------- +- Batch execution support (use the option -OIDAPython:yourscript.py) +- Added ScriptBox - lists previously run scripts (Hotkey:Alt-7) +- Added support for IDA Pro 4.8 (both Linux and Windows) +- Dropped support for IDA Pro 4.6 and 4.6SP1 versions +- Wrapped the list chooser (see examples/choose.py) +- A dozen or so IDC functions added +- Lots of char * API calls wrapped +- Added Python error handling in the plugin C layer +- Bunch of misc small cleanups and fixes +- For more details see CHANGES-SWIG.txt and CHANGES-Plugin.txt + +- API CHANGE: {Next|Prev}Function() return BADADDR instead of -1 + + +Changes from version 0.5.0 to 0.6.0 +----------------------------------- +- Added support for IDA Pro 4.7 (both Linux and Windows) +- Dropped support for IDA Pro 4.6SP1 beta on Linux +- Lots of IDC wrapper additions and fixes: + - Added 30+ new wrappers to idc.py + - Most Find*, Ask* and Seg* are now wrapped + - Fixed broken NextAddr(), PrevAddr(), MakeFunction() and MakeName() +- Fixes to the makefile +- Cleanups for the idaapi wrapper +- Bunch of misc small cleanups and fixes +- For more details see CHANGES-SWIG.txt and CHANGES-Plugin.txt + + diff --git a/COPYING.txt b/COPYING.txt new file mode 100644 index 0000000..8929aba --- /dev/null +++ b/COPYING.txt @@ -0,0 +1,27 @@ +Copyright (c) 2004-2007 Gergely Erdelyi . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. The name of the author may not be used to endorse or promote products +derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. + + diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..8207376 --- /dev/null +++ b/README.txt @@ -0,0 +1,70 @@ +---------------------------------------------------------- +IDAPython - Python plugin for Interactive Disassembler Pro +---------------------------------------------------------- + +WHAT IS IDAPTYHON? + +IDAPython is an IDA plugin which makes it possible to write scripts +for IDA in the Python programming language. IDAPython provides full +access to both the IDA API and any installed Python module. + +Check the scripts in the examples directory to get an quick glimpse. + + +AVAILABILITY + +Latest versions of IDAPython are available from + +http://www.d-dome.net/idapython/ + + +INSTALLATION FROM BINARIES + +1, Install Python 2.4 or 2.5 from http://www.python.org/ +2, Copy the directory python\ to the IDA install directory +3. Copy the plugin to the %IDADIR%\plugins\ + + +USAGE + +The plugin has three hotkeys: + + - Run script (Alt-9) + - Execute Python statement(s) (Alt-8) + - Run previously executed script again (Alt-7) + +Batch mode execution: + +Start IDA with the following command line options: + + -A -OIDAPython:yourscript.py file_to_work_on + +If you want fully unattended execution mode, make sure your script +exits with a qexit() call. + + +User init file: + +You can place your custom settings to a file called 'idapythonrc.py' +that should be placed to + +${HOME}/.idapro/ + +or + +C:\Documents and Settings\%USER%\Application Data\Datarescue\IDA Pro + +The user init file is read and executed at the end of the init process. + + +THANKS + +This project is sponsored by F-Secure Corporation by allowing me to +use some company time and resources for development. Please note that +F-Secure is only sponsoring the project, the company does not provide +any formal support for this software. Questions, comments, bug reports +should be directed to the author. + +F-Secure Corporation's website is located at + +http://www.F-Secure.com/ diff --git a/STATUS.txt b/STATUS.txt new file mode 100644 index 0000000..da7580c --- /dev/null +++ b/STATUS.txt @@ -0,0 +1,72 @@ +Status of the IDC wrapper +------------------------- + +6 function unimplemented out of 434 (98% coverage): + +rotate_left +XRefType +SetMemberType +GetType +GuessType +SetType + + +Status of IDA API wrappers +-------------------------- + +COMPLETE: all possible functions wrapped, no SWIG ifdefs +INCOMPLETE: some wrapping or SWIG ifdefs still left +EXCLUDED: will not be wrapped + +allins.hpp - COMPLETE +area.hpp - INCOMPLETE (SWIGdefs left) +auto.hpp - COMPLETE +bytes.hpp - INCOMPLETE (no SWIGs, some unwrapped) +compress.hpp - EXCLUDED +dbg.hpp - INCOMPLETE (SWIGs and lot of fixing to do) +demangle.hpp - EXCLUDED +diskio.hpp - INCOMPLETE (no SWIGs, some unwrapped) +entry.hpp - COMPLETE +enum.hpp - INCOMPLETE (no SWIGs, one FIXME) +err.h - EXCLUDED +exehdr.h - EXCLUDED +expr.hpp - INCOMPLETE (wrapped, needs testing) +fixup.hpp - COMPLETE +fpro.h - EXCLUDED +frame.hpp - COMPLETE +funcs.hpp - INCOMPLETE (some SWIGs, few FIXMEs) +gdl.hpp - EXCLUDED +graph.hpp - EXCLUDED +help.h - EXCLUDED +ida.hpp - INCOMPLETE (SWIGs) +idd.hpp - INCOMPLETE (SWIGs) +idp.hpp - INCOMPLETE (SWIGs) +ieee.h - EXCLUDED +intel.hpp - EXCLUDED +ints.hpp - INCOMPLETE (SWIGs) +kernwin.hpp - INCOMPLETE (SWIGs and lot of fixing to do) +lex.hpp - EXCLUDED +lines.hpp - INCOMPLETE (few FIXMEs) +llong.hpp - EXCLUDED +loader.hpp - INCOMPLETE (few FIXMEs) +md5.h - EXCLUDED +moves.hpp - COMPLETE (some needed SWIGs) +nalt.hpp - INCOMPLETE (SWIGs and lot of fixing to do) +name.hpp - INCOMPLETE (few FIXMEs) +netnode.hpp - INCOMPLETE (not wrapped at all) +offset.hpp - COMPLETE +prodir.h - EXCLUDED +pro.h - COMPLETE (some needed SWIGs) +queue.hpp - INCOMPLETE (one FIXME) +regex.h - EXCLUDED +search.hpp - INCOMPLETE (one FIXME) +segment.hpp - INCOMPLETE (no SWIGs, few FIXMEs) +sistack.hpp - EXCLUDED +srarea.hpp - INCOMPLETE (not wrapped at all) +strlist.hpp - COMPLETE +struct.hpp - COMPLETE +typeinf.hpp - INCOMPLETE (no SWIGs, lot of fixing to do) +ua.hpp - INCOMPLETE (SWIGs and lot of fixing to do) +va.hpp - EXCLUDED +vm.hpp - EXCLUDED +xref.hpp - COMPLETE diff --git a/basetsd.h b/basetsd.h new file mode 100644 index 0000000..be25793 --- /dev/null +++ b/basetsd.h @@ -0,0 +1,4 @@ +#ifndef _BASETSD_H +#define _BASETSD_H +/* Microsoft free compilers seem to lack this file and Python needs it */ +#endif diff --git a/build.py b/build.py new file mode 100644 index 0000000..c764e8c --- /dev/null +++ b/build.py @@ -0,0 +1,408 @@ +#!/usr/bin/env python +#------------------------------------------------------------ +# IDAPython - Python plugin for Interactive Disassembler Pro +# +# Copyright (c) 2004-2007 Gergely Erdelyi +# +# All rights reserved. +# +# For detailed copyright information see the file COPYING in +# the root of the distribution archive. +#------------------------------------------------------------ +# build.py - Custom build script +#------------------------------------------------------------ +import os, sys, platform, types, shutil +from distutils import sysconfig + +# Start of user configurable options +VERBOSE = True +IDA_MAJOR_VERSION = 5 +IDA_MINOR_VERSION = 1 +IDA_SDK = ".." + os.sep + "swigsdk-versions" + os.sep + "%d.%d" % (IDA_MAJOR_VERSION, IDA_MINOR_VERSION) +# End of user configurable options + +# IDAPython version +VERSION_MAJOR = 0 +VERSION_MINOR = 9 +VERSION_PATCH = 53 + +# Determine Python version +PYTHON_MAJOR_VERSION = int(platform.python_version()[0]) +PYTHON_MINOR_VERSION = int(platform.python_version()[2]) + +# Find Python headers +PYTHON_INCLUDE_DIRECTORY = sysconfig.get_config_var('INCLUDEPY') + +# Swig command-line parameters +SWIG_OPTIONS = '-modern -python -c++ -shadow -D__GNUC__' + +# Common macros for all compilations +COMMON_MACROS = [ + ("VER_MAJOR", "%d" % VERSION_MAJOR), + ("VER_MINOR", "%d" % VERSION_MINOR), + ("VER_PATCH", "%d" % VERSION_PATCH), + "__IDP__", + ("MAXSTR", "1024"), + "USE_DANGEROUS_FUNCTIONS", + "USE_STANDARD_FILE_FUNCTIONS" ] + +# Common includes for all compilations +COMMON_INCLUDES = [ ".", "swig" ] + +# List files for the binary distribution +BINDIST_MANIFEST = [ + "README.txt", + "COPYING.txt", + "CHANGES.txt", + "STATUS.txt", + "python/init.py", + "python/idc.py", + "python/idautils.py", + ("idaapi.py", "python"), + "docs/notes.txt", + "examples/chooser.py", + "examples/ex1.idc", + "examples/ex1_idaapi.py", + "examples/ex1_idautils.py" ] + +# List files for the source distribution (appended to binary list) +SRCDIST_MANIFEST = [ + "BUILDING.txt", + "python.cpp", + "basetsd.h", + "build.py", + "swig/auto.i", + "swig/bytes.i", + "swig/dbg.i", + "swig/diskio.i", + "swig/entry.i", + "swig/enum.i", + "swig/expr.i", + "swig/fixup.i", + "swig/frame.i", + "swig/funcs.i", + "swig/ida.i", + "swig/idaapi.i", + "swig/idp.i", + "swig/ints.i", + "swig/kernwin.i", + "swig/lines.i", + "swig/loader.i", + "swig/moves.i", + "swig/nalt.i", + "swig/name.i", + "swig/offset.i", + "swig/pro.i", + "swig/queue.i", + "swig/search.i", + "swig/segment.i", + "swig/srarea.i", + "swig/strlist.i", + "swig/struct.i", + "swig/typeconv.i", + "swig/typeinf.i", + "swig/ua.i", + "swig/xref.i", + "patches/ida51.patch" +] + +# Temporaty build files to remove +BUILD_TEMPFILES = [ + "idaapi.cpp", + "idaapi.obj", + "idaapi.o", + "idaapi.py", + "idapython.sln", + "idapython.ncb", + "python.exp", + "python.lib", + "python.obj" +] + +class BuilderBase: + """ Base class for builders """ + def __init__(self): + pass + + def compile(self, source, objectname=None, includes=[], macros=[]): + """ + Compile the source file + """ + allmacros = [] + allmacros.extend(COMMON_MACROS) + allmacros.extend(self.basemacros) + allmacros.extend(macros) + macrostring = self._build_command_string(allmacros, self.macro_delimiter) + + allincludes = [] + allincludes.extend(COMMON_INCLUDES) + allincludes.extend(includes) + includestring = self._build_command_string(allincludes, self.include_delimiter) + + if not objectname: + objectname = source + self.object_extension + + cmdstring = "%s %s %s %s %s %s" % (self.compiler, + self.compiler_parameters, + self.compiler_out_string(objectname), + self.compiler_in_string(source + self.source_extension), + includestring, + macrostring) + + if VERBOSE: print cmdstring + return os.system(cmdstring) + + + def link(self, objects, outfile, libpaths=[], libraries=[], extra_parameters=None): + """ Link the binary from objects and libraries """ + cmdstring = "%s %s %s" % (self.linker, + self.linker_parameters, + self.linker_out_string(outfile)) + + for objectfile in objects: + cmdstring = "%s %s" % (cmdstring, objectfile + self.object_extension) + + for libpath in libpaths: + cmdstring = "%s %s%s" % (cmdstring, self.libpath_delimiter, libpath) + + for library in libraries: + cmdstring = "%s %s" % (cmdstring, library) + + if extra_parameters: + cmdstring = "%s %s" % (cmdstring, extra_parameters) + + if VERBOSE: print cmdstring + return os.system(cmdstring) + + + def _build_command_string(self, macros, argument_delimiter): + macrostring = "" + + for item in macros: + if type(item) == types.TupleType: + macrostring += '%s%s="%s" ' % (argument_delimiter, item[0], item[1]) + else: + macrostring += '%s%s ' % (argument_delimiter, item) + + return macrostring + + +class GCCBuilder(BuilderBase): + """ Generic GCC compiler class """ + def __init__(self): + self.include_delimiter = "-I" + self.macro_delimiter = "-D" + self.libpath_delimiter = "-L" + self.compiler_parameters = "" + self.linker_parameters = "-shared" + self.basemacros = [ ] + self.compiler = "g++" + self.linker = "g++" + self.source_extension = ".cpp" + self.object_extension = ".o" + + def compiler_in_string(self, filename): + return "-c %s" % filename + + def compiler_out_string(self, filename): + return "-o %s" % filename + + def linker_out_string(self, filename): + return "-o %s" % filename + + +class MSVCBuilder(BuilderBase): + """ Generic GCC compiler class """ + def __init__(self): + self.include_delimiter = "/I" + self.macro_delimiter = "/D" + self.libpath_delimiter = "/LIBPATH:" + self.compiler_parameters = "/nologo /EHsc" + self.linker_parameters = "/nologo /dll /export:PLUGIN" + self.basemacros = [ "WIN32", + "_USRDLL", + "__NT__" ] + self.compiler = "cl" + self.linker = "link" + self.source_extension = ".cpp" + self.object_extension = ".obj" + + def compiler_in_string(self, filename): + return "/c %s" % filename + + def compiler_out_string(self, filename): + return "/Fo%s" % filename + + def linker_out_string(self, filename): + return "/out:%s" % filename + + +def build_distribution(manifest, distrootdir): + """ Create dist tree and copy files to it """ + + # Remove the previous distibution if exits + if os.path.exists(distrootdir): + shutil.rmtree(distrootdir) + + # Create output directory + os.makedirs(distrootdir) + + # Copy files, one by one + for f in manifest: + if type(f) == types.TupleType: + srcfilepath = f[0] + srcfilename = os.path.basename(srcfilepath) + dstdir = distrootdir + os.sep + f[1] + dstfilepath = dstdir + os.sep + srcfilename + else: + srcfilepath = f + srcfilename = os.path.basename(f) + srcdir = os.path.dirname(f) + + if srcdir == "": + dstdir = distrootdir + else: + dstdir = distrootdir + os.sep + srcdir + + if not os.path.exists(dstdir): + os.makedirs(dstdir) + + dstfilepath = dstdir + os.sep + srcfilename + + shutil.copyfile(srcfilepath, dstfilepath) + + +def build_plugin(system, idasdkdir): + """ Build the plugin from the SWIG wrapper and plugin main source """ + + # Find IDA SDK headers + ida_include_directory = idasdkdir + os.sep + "include" + + # Platform-specific settings for the Linux build + if system == "Linux": + builder = GCCBuilder() + plugin_name = "python.plx" + platform_macros = [ "__LINUX__" ] + python_libpath = sysconfig.EXEC_PREFIX + os.sep + "lib" + python_library = "-lpython%d.%d" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION) + ida_libpath = idasdkdir + os.sep + "libgcc32.lnx" + ida_lib = "" + extra_link_parameters = "/usr/lib/python%s.%s/lib-dynload/*.so" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION) + + # Platform-specific settings for the Windows build + if system == "Windows": + builder = MSVCBuilder() + plugin_name = "python.plw" + platform_macros = [ "__NT__" ] + python_libpath = sysconfig.EXEC_PREFIX + os.sep + "libs" + python_library = "python%d%d.lib" % (PYTHON_MAJOR_VERSION, PYTHON_MINOR_VERSION) + ida_libpath = idasdkdir + os.sep + "libvc.w32" + ida_lib = "ida.lib" + extra_link_parameters = None + + # Platform-specific settings for the Linux build + if system == "Darwin": + builder = GCCBuilder() + builder.linker_parameters = "-dynamiclib" + plugin_name = "python.pmc" + platform_macros = [ "__MAC__" ] + python_libpath = "." + python_library = "-framework Python" + ida_libpath = idasdkdir + os.sep + "libgcc32.mac" + ida_lib = "-lida" + extra_link_parameters = "" + + + # Build the wrapper from the interface files + swigcmd = "swig %s -Iswig -o idaapi.cpp -I%s idaapi.i" % (SWIG_OPTIONS, ida_include_directory) + if VERBOSE: print swigcmd + res = os.system(swigcmd) + + if res != 0: return False + + # Compile the wrapper + res = builder.compile("idaapi", + includes=[ PYTHON_INCLUDE_DIRECTORY, ida_include_directory ], + macros=platform_macros) + + if res != 0: return False + + # Compile the main plugin source + res = builder.compile("python", + includes=[ PYTHON_INCLUDE_DIRECTORY, ida_include_directory ], + macros=platform_macros) + + if res != 0: return False + + # Link the final binary + res = builder.link( ["idaapi", "python"], + plugin_name, + [ python_libpath, ida_libpath ], + [ python_library, ida_lib ], + extra_link_parameters) + + if res != 0: return False + + return True + + +def clean(manifest): + """ Clean the temporary files """ + + for i in manifest: + try: + os.unlink(i) + except: + pass + + +if __name__ == "__main__": + # Detect the platform + system = platform.system() + + if system == "Windows": + platform_string = "win32" + plugin_name = "python.plw" + + if system == "Linux": + platform_string = "linux" + plugin_name = "python.plx" + + if system == "Darwin": + platform_string = "macosx" + plugin_name = "python.pmc" + + BINDISTDIR = "idapython-%d.%d.%d_ida%d.%d_py%d.%d_%s" % ( VERSION_MAJOR, + VERSION_MINOR, + VERSION_PATCH, + IDA_MAJOR_VERSION, + IDA_MINOR_VERSION, + PYTHON_MAJOR_VERSION, + PYTHON_MINOR_VERSION, + platform_string) + SRCDISTDIR = "idapython-%d.%d.%d" % ( VERSION_MAJOR, + VERSION_MINOR, + VERSION_PATCH ) + + # Build the plugin + res = build_plugin(system, IDA_SDK) + if not res: sys.exit(1) + + # Build the binary distribution + binmanifest = [] + binmanifest.extend(BINDIST_MANIFEST) + binmanifest.append((plugin_name, "plugins")) + build_distribution(binmanifest, BINDISTDIR) + + # Build the binary distribution + srcmanifest = [] + srcmanifest.extend(BINDIST_MANIFEST) + srcmanifest.extend(SRCDIST_MANIFEST) + build_distribution(srcmanifest, SRCDISTDIR) + + # Clean the temp files + cleanlist = [] + cleanlist.extend(BUILD_TEMPFILES) + cleanlist.append(plugin_name) + clean(cleanlist) + diff --git a/docs/notes.txt b/docs/notes.txt new file mode 100644 index 0000000..e1dbf0a --- /dev/null +++ b/docs/notes.txt @@ -0,0 +1,53 @@ +Assorted notes +-------------- + +Wrapped functions and constants: + +All the symbols from the idaapi module are listed in symbollist.txt. +Documentation for the plugin API functions functions is in the IDA +SDK header files. All function and symbol names directly translate +to the C++ counterparts. If you try to use a function that is not +wrapped yet you will get an exception like this: + + Traceback (most recent call last): + File "", line 1, in ? + NameError: name 'foobar' is not defined + +If this happens you can check the function in symbollist.txt. If it +is not included and it should be please report it to the author. + + +Data types: + +All the C++ data types are mapped to corresponding Python data types. +For example ea_t maps to a Python integer. Complex data types (like +structures and classes) are mapped to Python classes that have the +same attributes as the original type. + + +Arguments and return values: + +Generally all function arguments should be the same type as specified +by the original headers. Pointers to complex types (structures, classes) +are checked and must match the original declarations. + +For example comment = get_func_comment("aa", 0) will raise an exception: + + Traceback (most recent call last): + File "", line 1, in ? + TypeError: Type error. Got aa, expected _p_func_t + +When calling functions that return a string in a buffer (usually with +maximum size) the buffer and size parameter is omitted. These functions +return either the result in a string or None if the call fails and returns +NULL. The output buffers are maximized at MAXSTR. + + Example: + + C++: get_func_name(0x1234, buf, sizeof(buf)); + Python: name = get_func_name(0x1234) + +Any function that should return a char * is going to return either a +Python string (up to MAXSTR) or None. + + diff --git a/examples/chooser.py b/examples/chooser.py new file mode 100644 index 0000000..87a0949 --- /dev/null +++ b/examples/chooser.py @@ -0,0 +1,46 @@ +# +# Demonstration of the new chooser usage +# + + +# +# Modal chooser +# + +# Get a modal Choose instance +chooser = Choose([], "MyChooser", 1) +# List to choose from +chooser.list = [ "First", "Second", "Third" ] +# Set the width +chooser.width = 50 +# Run the chooser +ch = chooser.choose() +# Print the results +if ch > 0: + print "You chose %d which is %s" % (ch, chooser.list[ch-1]) +else: + print "Escape from chooser" + + +# +# Normal chooser +# +class MyChoose(Choose): + """ + You have to subclass Chooser to override the enter() method + """ + def __init__(self, list=[], name="Choose"): + Choose.__init__(self, list, name) + # Set the width + self.width = 50 + + def enter(self, n): + print "Enter called. Do some stuff here." + print "The chosen item is %d = %s" % (n, self.list[n-1]) + print "Now press ESC to leave." + +# Get a Choose instance +chooser = MyChoose([ "First", "Second", "Third" ], "MyChoose") +# Run the chooser +ch = chooser.choose() + diff --git a/examples/ex1.idc b/examples/ex1.idc new file mode 100644 index 0000000..a0916d3 --- /dev/null +++ b/examples/ex1.idc @@ -0,0 +1,35 @@ +// +// Reference Lister +// +// List all functions and all references to them in the current section. +// +// Implemented in IDC +// +#include + +static main() +{ + auto ea, func, ref; + + // Get current ea + ea = ScreenEA(); + + // Loop from start to end in the current segment + for (func=SegStart(ea); + func != BADADDR && func < SegEnd(ea); + func=NextFunction(func)) + { + // If the current address is function process it + if (GetFunctionFlags(func) != -1) + { + Message("Function %s at 0x%x\n", GetFunctionName(func), func); + + // Find all code references to func + for (ref=RfirstB(func); ref != BADADDR; ref=RnextB(func, ref)) + { + Message(" called from %s(0x%x)\n", GetFunctionName(ref), ref); + } + + } + } +} diff --git a/examples/ex1_idaapi.py b/examples/ex1_idaapi.py new file mode 100644 index 0000000..3fec86a --- /dev/null +++ b/examples/ex1_idaapi.py @@ -0,0 +1,29 @@ +# +# Reference Lister +# +# List all functions and all references to them in the current section. +# +# Implemented using direct IDA Plugin API calls +# +from idaapi import * + +# Get current ea +ea = get_screen_ea() + +# Get segment class +seg = getseg(ea) + +# Loop from segment start to end +func = get_func(seg.startEA) + +while func != None and func.startEA < seg.endEA: + funcea = func.startEA + print "Function %s at 0x%x" % (GetFunctionName(funcea), funcea) + + ref = get_first_cref_to(funcea) + + while ref != BADADDR: + print " called from %s(0x%x)" % (get_func_name(ref), ref) + ref = get_next_cref_to(funcea, ref) + + func = get_next_func(funcea) diff --git a/examples/ex1_idautils.py b/examples/ex1_idautils.py new file mode 100644 index 0000000..d0d76b7 --- /dev/null +++ b/examples/ex1_idautils.py @@ -0,0 +1,20 @@ +# +# Reference Lister +# +# List all functions and all references to them in the current section. +# +# Implemented with the idautils module +# +from idautils import * + +# Get current ea +ea = ScreenEA() + +# Loop from start to end in the current segment +for funcea in Functions(SegStart(ea), SegEnd(ea)): + print "Function %s at 0x%x" % (GetFunctionName(funcea), funcea) + + # Find all code references to funcea + for ref in CodeRefsTo(funcea, 1): + print " called from %s(0x%x)" % (GetFunctionName(ref), ref) + diff --git a/patches/ida51.patch b/patches/ida51.patch new file mode 100644 index 0000000..eda6878 --- /dev/null +++ b/patches/ida51.patch @@ -0,0 +1,826 @@ +diff -ur idasdk-versions/5.1/include/area.hpp swigsdk-versions/5.1/include/area.hpp +--- idasdk-versions/5.1/include/area.hpp 2006-09-20 17:37:08.000000000 +0300 ++++ swigsdk-versions/5.1/include/area.hpp 2007-09-30 06:56:51.000000000 +0300 +@@ -57,6 +57,7 @@ + }; + + ++#ifndef SWIG + // Internal classes + + class sarray; // sorted array - keeps information in Btree. +@@ -603,6 +604,7 @@ + { return areacb_t_for_all_areas(this, ea1, ea2, av, ud); } + + }; ++#endif // SWIG + + + // Last request information -- for internal use +diff -ur idasdk-versions/5.1/include/bytes.hpp swigsdk-versions/5.1/include/bytes.hpp +--- idasdk-versions/5.1/include/bytes.hpp 2007-01-22 04:07:12.000000000 +0200 ++++ swigsdk-versions/5.1/include/bytes.hpp 2007-09-30 06:56:51.000000000 +0300 +@@ -1644,9 +1644,9 @@ + const uchar *mask, // comparision mask + size_t len, // length of string to search + int step, // direction: ++ int flags); + #define BIN_SEARCH_FORWARD 1 + #define BIN_SEARCH_BACKWARD (-1) +- int flags); + #define BIN_SEARCH_CASE 0x01 + #define BIN_SEARCH_NOCASE 0x00 + #define BIN_SEARCH_NOBREAK 0x02 +diff -ur idasdk-versions/5.1/include/dbg.hpp swigsdk-versions/5.1/include/dbg.hpp +--- idasdk-versions/5.1/include/dbg.hpp 2006-11-20 13:18:02.000000000 +0200 ++++ swigsdk-versions/5.1/include/dbg.hpp 2007-09-30 06:56:51.000000000 +0300 +@@ -31,6 +31,7 @@ + + idaman debugger_t ida_export_data *dbg; // Current debugger - NULL if no debugger + ++#ifndef SWIG + //-------------------------------------------------------------------- + // D E B U G G E R C A L L B A C K S + //-------------------------------------------------------------------- +@@ -519,6 +520,7 @@ + // Notification: none (synchronous function) + + bool idaapi is_reg_integer(const char *regname); ++#endif // SWIG + + //-------------------------------------------------------------------- + // B R E A K P O I N T S +@@ -543,6 +545,7 @@ + }; + + ++#ifndef SWIG + // Get number of breakpoints. + // Type: Synchronous function + // Notification: none (synchronous function) +@@ -779,6 +782,7 @@ + //-------------------------------------------------------------------- + // T R A C I N G E V E N T S + //-------------------------------------------------------------------- ++#endif // SWIG + + // Trace event types: + enum tev_type_t +@@ -799,6 +803,7 @@ + }; + + ++#ifndef SWIG + // Get number of trace events available in trace buffer. + // Type: Synchronous function + // Notification: none (synchronous function) +@@ -877,6 +882,7 @@ + // corresponds to a valid breakpoint. + + ea_t idaapi get_bpt_tev_ea(int n); ++#endif // SWIG + + //-------------------------------------------------------------------- + // Utility functions +diff -ur idasdk-versions/5.1/include/expr.hpp swigsdk-versions/5.1/include/expr.hpp +--- idasdk-versions/5.1/include/expr.hpp 2006-04-12 16:29:34.000000000 +0300 ++++ swigsdk-versions/5.1/include/expr.hpp 2007-09-30 06:56:51.000000000 +0300 +@@ -37,12 +37,16 @@ + number of arguments. The actual number of + arguments will be passed in res->num */ + ++#ifndef SWIG + union + { ++#endif // SWIG + char *str; /* T_str */ + sval_t num; /* T_long */ + ushort e[6]; /* T_flt */ ++#ifndef SWIG + }; ++#endif // SWIG + }; + + +diff -ur idasdk-versions/5.1/include/funcs.hpp swigsdk-versions/5.1/include/funcs.hpp +--- idasdk-versions/5.1/include/funcs.hpp 2007-02-17 21:04:02.000000000 +0200 ++++ swigsdk-versions/5.1/include/funcs.hpp 2007-09-30 06:56:51.000000000 +0300 +@@ -88,10 +88,12 @@ + bool is_far(void) const { return (flags & FUNC_FAR) != 0; } + bool does_return(void) const { return (flags & FUNC_NORET) == 0; } + bool analyzed_sp(void) const { return (flags & FUNC_SP_READY) != 0; } ++#ifndef SWIG + union + { + struct // attributes of a function entry chunk + { ++#endif // SWIG + // + // Stack frame of the function. It is represented as a structure: + // +@@ -147,15 +149,19 @@ + int tailqty; // number of function tails + area_t *tails; // array of tails, sorted by ea + // use func_tail_iterator_t to access function tails ++#ifndef SWIG + }; + struct // attributes of a function tail chunk + { ++#endif // SWIG + ea_t owner; // the address of the main function possessing this tail + int refqty; // number of referers + ea_t *referers; // array of referers (function start addresses) + // use func_parent_iterator_t to access the referers ++#ifndef SWIG + }; + }; ++#endif // SWIG + }; + + inline bool is_func_entry(const func_t *pfn) { return pfn != NULL && (pfn->flags & FUNC_TAIL) == 0; } +diff -ur idasdk-versions/5.1/include/ida.hpp swigsdk-versions/5.1/include/ida.hpp +--- idasdk-versions/5.1/include/ida.hpp 2007-01-31 16:35:16.000000000 +0200 ++++ swigsdk-versions/5.1/include/ida.hpp 2007-09-30 06:56:51.000000000 +0300 +@@ -369,6 +369,7 @@ + inline bool idaapi should_create_stkvars(void) { return (inf.af & AF_LVAR) != 0; } + + ++#ifndef SWIG + // set a 'bit' in 'where' if 'value' if not zero + + inline void idaapi setflag(uchar &where,uchar bit,int value) +@@ -390,10 +391,13 @@ + else where &= ~bit; + } + ++#endif // SWIG + //------------------------------------------------------------------------// + ++#ifndef SWIG + #define BADADDR ea_t(-1) // this value is used for 'bad address' + #define BADSEL sel_t(-1) // 'bad selector' value ++#endif // SWIG + + // Maximum address allowed to use in the program being disassebled. + // This is obsolete, don't use it! +diff -ur idasdk-versions/5.1/include/idd.hpp swigsdk-versions/5.1/include/idd.hpp +--- idasdk-versions/5.1/include/idd.hpp 2006-12-08 16:52:40.000000000 +0200 ++++ swigsdk-versions/5.1/include/idd.hpp 2007-09-30 06:56:51.000000000 +0300 +@@ -53,6 +53,7 @@ + char name[MAXSTR]; + }; + ++#ifndef SWIG + //==================================================================== + // + // Registers +@@ -173,6 +174,7 @@ + e_exception_t exc; // EXCEPTION + }; + }; ++#endif // SWIG + + // Hardware breakpoint types + typedef int bpttype_t; +@@ -183,6 +185,7 @@ + BPT_SOFT = 4; // Software breakpoint + + ++#ifndef SWIG + // Exception information + struct exception_info_t + { +@@ -441,6 +444,7 @@ + #error "Size of debugger_t is incorrect" + #endif + #endif ++#endif // SWIG + + #pragma pack(pop) + #endif // _IDD_HPP +diff -ur idasdk-versions/5.1/include/idp.hpp swigsdk-versions/5.1/include/idp.hpp +--- idasdk-versions/5.1/include/idp.hpp 2007-02-09 12:54:06.000000000 +0200 ++++ swigsdk-versions/5.1/include/idp.hpp 2007-09-30 06:56:51.000000000 +0300 +@@ -31,6 +31,7 @@ + + #define IDP_INTERFACE_VERSION 76 + ++#ifndef SWIG + //----------------------------------------------------------------------- + // AbstractRegister and WorkReg are deprecated! + class WorkReg; +@@ -110,6 +111,7 @@ + #define CF_HLL 0x10000 // Instruction may be present in a high level + // language function. + }; ++#endif // SWIG + + idaman bool ida_export InstrIsSet(int icode,int bit); // does the specified instruction + // have the specified feature? +@@ -119,6 +121,7 @@ + idaman bool ida_export is_indirect_jump_insn(ea_t ea); + idaman bool ida_export is_basic_block_end(bool call_insn_stops_block); // in:cmd + ++#ifndef SWIG + //----------------------------------------------------------------------- + // Structures related to checkarg_dispatch() + +@@ -1384,6 +1387,7 @@ + int high_fixup_bits; + + }; ++#endif // SWIG + + #ifdef __BORLANDC__ + #if sizeof(processor_t) % 4 +@@ -1394,8 +1398,10 @@ + // The following two structures contain information about the current + // processor and assembler. + ++#ifndef SWIG + idaman processor_t ida_export_data ph; // Current processor + idaman asm_t ida_export_data ash; // Current assembler ++#endif // SWIG + + idaman int ida_export str2regf(const char *p); // -1 - error. Returns word reg number + idaman int ida_export str2reg(const char *p); // -1 - error. Returns any reg number +@@ -1500,10 +1506,12 @@ + idaman char *ida_export get_idp_name(char *buf, size_t bufsize); + + ++#ifndef SWIG + // Unload the processor module. + // This function is for the kernel only. + + void free_processor_module(void); ++#endif // SWIG + + + // Set target assembler +@@ -1512,11 +1520,13 @@ + idaman void ida_export set_target_assembler(int asmnum); + + ++#ifndef SWIG + // Read IDA.CFG file and configure IDA for the current processor + // This is an internal kernel function. + // It should not be used in modules. + + void read_config_file(int npass); ++#endif // SWIG + + + // get number of bits in a byte at the given address +diff -ur idasdk-versions/5.1/include/kernwin.hpp swigsdk-versions/5.1/include/kernwin.hpp +--- idasdk-versions/5.1/include/kernwin.hpp 2007-01-29 05:44:54.000000000 +0200 ++++ swigsdk-versions/5.1/include/kernwin.hpp 2007-09-30 06:56:51.000000000 +0300 +@@ -28,8 +28,10 @@ + #include + #include + ++#ifndef SWIG + typedef int atype_t; // autoanalysis types + typedef int idastate_t; // ida state indicator (ready, thinking, waiting) ++#endif // SWIG + typedef uchar color_t; // see + typedef uval_t bmask_t; // see + typedef tid_t enum_t; // see +@@ -95,6 +97,7 @@ + class value_t; + class linput_t; + ++#ifndef SWIG + union callui_t // Return codes (size of this type should be 4 bytes at most) + { // (otherwise different compilers return it differently) + bool cnd; +@@ -877,6 +880,8 @@ + idaman void ida_export vshow_hex_file(linput_t *li, long pos, size_t count, const char *format, va_list va); + + ++#endif // SWIG ++#ifndef SWIG + //-------------------------------------------------------------------------- + // K E R N E L S E R V I C E S F O R U I + //-------------------------------------------------------------------------- +@@ -1218,8 +1223,10 @@ + { return linearray_t_up(this); } + + }; ++#endif // SWIG + + ++#ifndef SWIG + //--------------------------------------------------------------------------- + // D E B U G G I N G F U N C T I O N S + //--------------------------------------------------------------------------- +@@ -1303,11 +1310,13 @@ + vshow_hex_file(li, pos, count, fmt, va); + va_end(va); + } ++#endif // SWIG + + //------------------------------------------------------------------------- + // U I S E R V I C E F U N C T I O N S + //------------------------------------------------------------------------- + ++#ifndef SWIG + // Common function prototypes + // These functions are inlined for the kernel + // They are not inlined for the user-interfaces +@@ -1466,6 +1475,7 @@ + sizer, getl, title, icon, deflt, del, + ins, update, edit, enter, destroy, popup_names, get_icon); + } ++#endif // SWIG + + // Navigation band colorizer function + // ea - address to calculate the color of +@@ -1570,6 +1580,7 @@ + + // Get VCL global variables + ++#ifndef SWIG + #if defined(__BORLANDC__) + namespace Forms + { +@@ -1590,6 +1601,7 @@ + } + + #endif // __BORLANDC__ ++#endif // SWIG + + #ifdef _WINDOWS_ + namespace Forms +@@ -1807,6 +1819,7 @@ + } + + ++#ifndef SWIG + // Pointer to idaview marker function. + // This pointer is initialized by callui(ui_get_marker) + +@@ -1839,6 +1852,7 @@ + if ( idaview_marker != NULL ) + idaview_marker(get_screen_ea()); + } ++#endif // SWIG + + + inline char *choose_idasgn(void) +@@ -1914,6 +1928,7 @@ + return callui(ui_choose, chtype_struc, title).strptr; + } + ++#ifndef SWIG + inline int choose_struc_path(const char *title, tid_t strid, + uval_t offset, adiff_t delta, bool appzero, tid_t *path) + { +@@ -1978,6 +1993,7 @@ + widths, sizer, getl, title, icon, deflt, del, ins, + update, edit, enter, destroy, popup_names, get_icon).i32; + } ++#endif // SWIG + + + // Display a dialog box with "Please wait..." +@@ -2309,6 +2325,7 @@ + return nbytes; + } + ++#ifndef SWIG + inline int Message(help_t format,...) + { + va_list va; +@@ -2317,8 +2334,10 @@ + va_end(va); + return nbytes; + } ++#endif // SWIG + + ++#ifndef SWIG + //---------------------------------------------------------------------- + // F O R M S - C O M P L E X D I A L O G B O X E S + //---------------------------------------------------------------------- +@@ -2534,6 +2553,7 @@ + + + */ ++#endif // SWIG + + //--------------------------------------------------------------------------- + // Y E S / N O D I A L O G B O X +@@ -2695,6 +2715,7 @@ + #define HIST_TYPE 8 // type declarations + + ++#ifndef SWIG + // Display a dialog box and wait for the user to input multiline text + // size - maximum size of text in bytes + // answer - output buffer. if you specify NULL then the answer +@@ -2719,6 +2740,7 @@ + va_end(va); + return result; + } ++#endif // SWIG + + + //--------------------------------------------------------------------------- +@@ -2794,6 +2816,7 @@ + idaman const char *ida_export strarray(const strarray_t *array, size_t array_size, int code); + + ++#ifndef SWIG + // Convert whitespace to tabulations + // This functin will stop the conversion as soon as a string or character constant + // is encountered +@@ -2986,6 +3009,7 @@ + // match a string with a regular expression + // returns: 0-no match, 1-match, -1-error + idaman int ida_export regex_match(const char *str, const char *pattern, bool sense_case); ++#endif // SWIG + + + #pragma pack(pop) +diff -ur idasdk-versions/5.1/include/lines.hpp swigsdk-versions/5.1/include/lines.hpp +--- idasdk-versions/5.1/include/lines.hpp 2006-03-17 17:41:22.000000000 +0200 ++++ swigsdk-versions/5.1/include/lines.hpp 2007-09-30 06:56:51.000000000 +0300 +@@ -614,12 +614,11 @@ + ml_getnam_t *getnam, + ml_genxrf_t *genxrf, + ml_saver_t *saver, +- int flags ++ int flags); + #define MAKELINE_NONE 0x00 + #define MAKELINE_BINPREF 0x01 + #define MAKELINE_VOID 0x02 + #define MAKELINE_STACK 0x04 +- ); + + idaman bool ida_export save_line_in_array(const char *line); // a standard line saver() + idaman void ida_export init_lines_array(char *lnar[],int maxsize);// initialization function for it +diff -ur idasdk-versions/5.1/include/moves.hpp swigsdk-versions/5.1/include/moves.hpp +--- idasdk-versions/5.1/include/moves.hpp 2006-03-17 17:41:22.000000000 +0200 ++++ swigsdk-versions/5.1/include/moves.hpp 2007-09-30 06:56:51.000000000 +0300 +@@ -26,6 +26,8 @@ + { return !(*this == r); } + }; + ++ ++#ifndef SWIG + // Helper functions. Should not be called directly! + class curloc; + class location_t; +@@ -49,13 +51,16 @@ + + DEFINE_CURLOC_HELPERS(idaman) + DEFINE_LOCATION_HELPERS(idaman) ++#endif // SWIG + + #define CURLOC_SISTACK_ITEMS 4 + + class curloc : public sistack_t + { + void push(void); ++#ifndef SWIG + DEFINE_CURLOC_HELPERS(friend) ++#endif // SWIG + void unhide_if_necessary(ea_t ea); + void hide_if_necessary(void); + protected: +@@ -120,7 +125,9 @@ + class location_t : public curloc + { + typedef curloc inherited; ++#ifndef SWIG + DEFINE_LOCATION_HELPERS(friend) ++#endif // SWIG + public: + graph_location_info_t gli; + location_t(void) {} +diff -ur idasdk-versions/5.1/include/nalt.hpp swigsdk-versions/5.1/include/nalt.hpp +--- idasdk-versions/5.1/include/nalt.hpp 2007-01-29 22:06:46.000000000 +0200 ++++ swigsdk-versions/5.1/include/nalt.hpp 2007-09-30 06:56:51.000000000 +0300 +@@ -29,6 +29,7 @@ + // in them. Look at netnode.hpp for the definition of netnodes. + // + ++#ifndef SWIG + #include + + //-------------------------------------------------------------------------- +@@ -324,6 +325,7 @@ + IMPL__IS_AFLAG_FUNCS(AFL_FIXEDSPD, fixed_spd) + IMPL__IS_AFLAG_FUNCS(AFL_ALIGNFLOW,align_flow) + IMPL__IS_AFLAG_FUNCS(AFL_USERTI, userti) ++#endif // SWIG + + inline void set_visible_item(ea_t ea, bool visible) + { +@@ -341,11 +343,14 @@ + + // source line numbers (they are sometimes present in object files) + // Thes functions may be used if necessary. ++#ifndef SWIG + NALT_EA(get_linnum0,set_linnum0, del_linnum0, NALT_LINNUM) ++#endif // SWIG + idaman void ida_export set_source_linnum(ea_t ea, uval_t lnnum); + idaman uval_t ida_export get_source_linnum(ea_t ea); // returns BADADDR if no lnnum + idaman void ida_export del_source_linnum(ea_t ea); + ++#ifndef SWIG + // absolute segment base address + // These functions may be used if necessary. + NALT_EA(get_absbase,set_absbase, del_absbase, NALT_ABSBASE) +@@ -366,6 +371,7 @@ + // type of string + // Don't use, see: get_typeinfo() + NALT_ULONG(get_str_type,set_str_type,del_str_type,NALT_STRTYPE) ++#endif // SWIG + + inline char idaapi get_str_type_code(uval_t strtype) { return char(strtype); } + +@@ -402,16 +408,19 @@ + } + + ++#ifndef SWIG + // alignment value (should be power of 2) + // These functions may be used if necessary. + NALT_ULONG(get_alignment,set_alignment,del_alignment,NALT_ALIGN) + + // instruction/data background color + NALT_ULONG(_get_item_color,_set_item_color,_del_item_color,NALT_COLOR) ++#endif // SWIG + idaman void ida_export set_item_color(ea_t ea, bgcolor_t color); + idaman bgcolor_t ida_export get_item_color(ea_t ea); // returns DEFCOLOR if no color + idaman void ida_export del_item_color(ea_t ea); + ++#ifndef SWIG + //---------------------------------------------------------------------- + NSUP_STRING(nalt_cmt,NSUP_CMT) // regular comment (low level, don't use) + NSUP_STRING(nalt_rptcmt,NSUP_REPCMT) // repeatable comment (low level, don't use) +@@ -559,6 +568,7 @@ + + // Address which holds the switch info. Used at the jump targets. + NALT_EA(get_switch_parent,set_switch_parent,del_switch_parent, NALT_SWITCH) ++#endif // SWIG + + + //-------------------------------------------------------------------------- +@@ -671,6 +681,7 @@ + idaman void ida_export write_struc_path(netnode node, int idx, const tid_t *path, int plen, adiff_t delta); + idaman int ida_export read_struc_path(netnode node, int idx, tid_t *path, adiff_t *delta); // returns plen + ++#ifndef SWIG + #define DEFINE_PATH_FUNCS(name, code) \ + inline int N_PASTE(get_,name)(ea_t ea, tid_t *path, adiff_t *delta) \ + { return read_struc_path(netnode(ea), code, path, delta); } \ +@@ -738,6 +749,7 @@ + #define RIDX_ALT_CRC32 uval_t(-5) // input file crc32 + #define RIDX_ALT_IMAGEBASE uval_t(-6) // image base + #define RIDX_ALT_IDSNODE uval_t(-7) // ids modnode id (for import_module) ++#endif // SWIG + + //-------------------------------------------------------------------------- + // Get full path of the input file +@@ -784,11 +796,13 @@ + return get_input_file_path(buf, bufsize); + } + ++#ifndef SWIG + #ifndef NO_OBSOLETE_FUNCS + #define SWI_SHIFT1 0x80 // use formula (element*2 + elbase) + // to find jump targets (obsolete) + NSUP_STRUCT(switch_info,NSUP_SWITCH) + #endif ++#endif // SWIG + + #ifndef BYTES_SOURCE // undefined bit masks so no one can use them directly + #undef AFL_LINNUM +diff -ur idasdk-versions/5.1/include/pro.h swigsdk-versions/5.1/include/pro.h +--- idasdk-versions/5.1/include/pro.h 2007-02-17 21:04:34.000000000 +0200 ++++ swigsdk-versions/5.1/include/pro.h 2007-09-30 06:56:51.000000000 +0300 +@@ -63,6 +63,7 @@ + #define __EA64__ + #endif + ++#ifndef SWIG + #ifdef __VC__ + #define ENUM_SIZE(t) : t + #else +@@ -138,6 +139,7 @@ + #define __KYLIX__ + #endif + ++#endif // SWIG + /*==================================================*/ + #ifndef MAXSTR + #define MAXSTR 1024 +@@ -178,7 +180,12 @@ + + /*==================================================*/ + +-#if defined(__IDP__) && defined(__NT__) // for modules ++#if defined(SWIG) // for SWIG ++#define idaapi ++#define idaman ++#define ida_export ++#define ida_export_data ++#elif defined(__IDP__) && defined(__NT__) // for modules + #define idaapi __stdcall + #define idaman EXTERNC + #define ida_export idaapi +@@ -237,7 +244,9 @@ + typedef unsigned long ulong; + #endif + ++#ifndef SWIG + #include ++#endif // SWIG + + typedef char int8; + typedef signed char sint8; +@@ -295,6 +304,7 @@ + typedef adiff_t sval_t; // signed value used by the processor + // for 32-bit ea_t, long + // for 64-bit ea_t, longlong ++#ifndef SWIG + #define BADADDR ea_t(-1) // this value is used for 'bad address' + + // Windows64 declarations +@@ -618,7 +628,9 @@ + idaman bool ida_export qisdir(const char *file); + + /*==================================================*/ ++#endif // SWIG + idaman void ida_export qexit(int code); ++#ifndef SWIG + idaman void ida_export qatexit(void (idaapi *func)(void)); + + /*==================================================*/ +@@ -1286,6 +1298,7 @@ + #define cwstr(dst, src, dstsize) qstrncpy(dst, src, dstsize) + #define wcstr(dst, src, dstsize) qstrncpy(dst, src, dstsize) + #endif ++#endif // SWIG + + // Old Visual C++ compilers were not defining the following: + #ifdef __NT__ +diff -ur idasdk-versions/5.1/include/ua.hpp swigsdk-versions/5.1/include/ua.hpp +--- idasdk-versions/5.1/include/ua.hpp 2006-10-24 23:19:54.000000000 +0300 ++++ swigsdk-versions/5.1/include/ua.hpp 2007-09-30 06:56:51.000000000 +0300 +@@ -42,10 +42,12 @@ + // in 'cmd' structure. They should not access to bytes of instruction + // and decode it again - this should be done in the analysis step. + ++#ifndef SWIG + #include // for btoa() + #include // for color_t + #include // add_cref() + #include // longlong ++#endif // SWIG + + //-------------------------------------------------------------------------- + // T Y P E O F O P E R A N D +@@ -223,13 +225,17 @@ + + // The following unions keep other information about the operand + ++#ifndef SWIG + union + { ++#endif // SWIG + ushort reg; // number of register (o_reg) + ushort phrase; // number of register phrase (o_phrase,o_displ) + // you yourself define numbers of phrases + // as you like ++#ifndef SWIG + }; ++#endif // SWIG + + bool is_reg(int r) const { return type == o_reg && reg == r; } + +@@ -238,7 +244,9 @@ + + // VALUE + ++#ifndef SWIG + union { ++#endif // SWIG + uval_t value; // value of operand (o_imm) + // outer displacement (o_displ+OF_OUTER_DISP) + +@@ -246,14 +254,18 @@ + ushort low; // your convenience only + ushort high; + } value_shorts; ++#ifndef SWIG + }; ++#endif // SWIG + + bool is_imm(uval_t v) const { return type == o_imm && value == v; } + + + // VIRTUAL ADDRESS (OFFSET WITHIN THE SEGMENT) + ++#ifndef SWIG + union { ++#endif // SWIG + ea_t addr; // virtual address pointed or used by the operand + // (o_mem,o_displ,o_far,o_near) + +@@ -261,18 +273,25 @@ + ushort low; // your convenience only + ushort high; + } addr_shorts; ++ ++#ifndef SWIG + }; ++#endif // SWIG + + + // IDP SPECIFIC INFORMATION + ++#ifndef SWIG + union { ++#endif // SWIG + ea_t specval; // This field may be used as you want. + struct { // this structure is defined for your convenience only + ushort low; // IBM PC: segment register number (o_mem,o_far,o_near) + ushort high; // IBM PC: segment selector value (o_mem,o_far,o_near) + } specval_shorts; ++#ifndef SWIG + }; ++#endif // SWIG + + // The following fields are used only in idp modules + // You may use them as you want to store additional information about +@@ -336,15 +355,19 @@ + // Additinal information about the instruction. + // You may use these field as you want. + ++#ifndef SWIG + union + { ++#endif // SWIG + ushort auxpref; // processor dependent field + struct + { + uchar low; + uchar high; + } auxpref_chars; ++#ifndef SWIG + }; ++#endif // SWIG + char segpref; // processor dependent field + char insnpref; // processor dependent field + +@@ -374,6 +397,7 @@ + + // This structure is used to pass values of bytes to helper functions. + ++#ifndef SWIG + union value_u + { + uchar v_char; +@@ -393,6 +417,7 @@ + // returns: number of immediate values (0..2*UA_MAXOP) + + idaman size_t ida_export get_operand_immvals(ea_t ea, int n, uval_t *v); ++#endif // SWIG + + + //-------------------------------------------------------------------------- +@@ -405,6 +430,7 @@ + idaman insn_t ida_export_data cmd; // current instruction + + ++#ifndef SWIG + // Undocumented variable. It is not used by the kernel. + // Its value may be specified in IDA.CFG: + // LOOKBACK = +@@ -810,6 +836,7 @@ + // Returns: the reference target address (the same as calc_reference_target) + + idaman ea_t ida_export ua_add_off_drefs(const op_t &x, dref_t type); ++#endif // SWIG + + + // Get size and flags for op_t.dtyp field. +@@ -871,6 +898,7 @@ + idaman const char *ida_export ua_mnem(ea_t ea, char *buf, size_t bufsize); + + ++#ifndef SWIG + //-------------------------------------------------------------------------- + // Helper functions for the processor emulator/analyzer + //-------------------------------------------------------------------------- +@@ -942,6 +970,7 @@ + // Also converts to code, uses fixups, increases segments etc + // This function is only for the kernel + // Use ua_code() instead ++#endif // SWIG + + #ifndef NO_OBSOLETE_FUNCS + idaman void ida_export ua_dodata(ea_t ea, int dtype); diff --git a/python.cpp b/python.cpp new file mode 100644 index 0000000..ef8d330 --- /dev/null +++ b/python.cpp @@ -0,0 +1,461 @@ +//------------------------------------------------------------ +// IDAPython - Python plugin for Interactive Disassembler Pro +// +// Copyright (c) 2004-2007 Gergely Erdelyi +// +// All rights reserved. +// +// For detailed copyright information see the file COPYING in +// the root of the distribution archive. +//------------------------------------------------------------ +// python.cpp - Main plugin code +//------------------------------------------------------------ +#include + +/* This define fixes the redefinition of ssize_t */ +#ifdef HAVE_SSIZE_T +#define _SSIZE_T_DEFINED 1 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" +#endif + +/* Python-style version tuple comes from the makefile */ +/* Only the serial and status is set here */ +#define VER_SERIAL 0 +#define VER_STATUS "final" + +#define IDAPYTHON_RUNFILE 0 +#define IDAPYTHON_RUNSTATEMENT 1 +#define IDAPYTHON_SCRIPTBOX 2 + +#define IDAPYTHON_DATA_STATEMENT 0 + + +void init_idaapi(void); +void idaapi run(int arg); + +static int initialized = 0; + + +/* This is a simple tracing code for debugging purposes. */ +/* It might evolve into a tracing facility for user scripts. */ +/* #define ENABLE_PYTHON_PROFILING */ + +#ifdef ENABLE_PYTHON_PROFILING +#include "compile.h" +#include "frameobject.h" + +int tracefunc(PyObject *obj, _frame *frame, int what, PyObject *arg) +{ + PyObject *str; + + /* Catch line change events. */ + /* Print the filename and line number */ + if (what == PyTrace_LINE) + { + str = PyObject_Str(frame->f_code->co_filename); + if (str) + { + msg("PROFILING: %s:%d\n", PyString_AsString(str), frame->f_lineno); + Py_DECREF(str); + } + } + return 0; +} +#endif + +/* QuickFix for the FILE* incompatibility problem */ +int ExecFile(char *FileName) +{ + PyObject* PyFileObject = PyFile_FromString(FileName, "r"); + + if (!PyFileObject) + { + return 0; + } + + if (PyRun_SimpleFile(PyFile_AsFile(PyFileObject), FileName) == 0) + { + Py_DECREF(PyFileObject); + return 1; + } + else + { + Py_DECREF(PyFileObject); + return 0; + } +} + +/* Check for the presence of a file in IDADIR/python */ +bool CheckFile(char *filename) +{ + char filepath[MAXSTR+1]; + +#if IDP_INTERFACE_VERSION >= 75 + qmakepath(filepath, MAXSTR, idadir(NULL), "python", filename, NULL); +#elif IDP_INTERFACE_VERSION >= 69 + qmakepath(filepath, idadir(NULL), "python", filename, NULL); +#else + qmakepath(filepath, idadir(), "python", filename, NULL); +#endif + + if (!qfileexist(filepath)) + { + warning("IDAPython: Missing required file %s", filename); + return false; + } + + return true; +} + +/* Execute the Python script from the plugin */ +/* Default hotkey: Alt-9 */ +void IDAPython_RunScript(char *script) +{ + char statement[MAXSTR+32]; + char slashpath[MAXSTR+1]; + char *scriptpath; + + int i; + + if (script) + { + scriptpath = script; + } + else + { + scriptpath = askfile_c(0, "*.py", "Python file to run"); + + if (!scriptpath) + { + return; + } + } + + /* Make a copy of the path with '\\' => '/' */ + for (i=0; scriptpath[i]; i++) + { + if (scriptpath[i] == '\\') + { + slashpath[i] = '/'; + } + else + { + slashpath[i] = scriptpath[i]; + } + } + + slashpath[i] = '\0'; + + /* Add the script't path to sys.path */ + snprintf(statement, sizeof(statement), "runscript(\"%s\")", slashpath); + PyRun_SimpleString(statement); + + /* Error handling */ + if (PyErr_Occurred()) + { + PyErr_Print(); + } + +} + + +/* Execute Python statement(s) from an editor window */ +/* Default hotkey: Alt-8 */ +void IDAPython_RunStatement(void) +{ + char statement[4096]; + netnode history; + + /* Get the existing or create a new netnode in the database */ + history.create("IDAPython_Data"); + + /* Fetch the previous statement */ + if (history.supval(IDAPYTHON_DATA_STATEMENT, statement, sizeof(statement)) == -1) + { + statement[0] = '\0'; + } + + if (asktext(sizeof(statement), statement, statement, "Enter Python expressions")) + { + PyRun_SimpleString(statement); + /* Store the statement to the database */ + history.supset(IDAPYTHON_DATA_STATEMENT, statement); + } +} + +/* History of previously executed scripts */ +/* Default hotkey: Alt-7 */ +void IDAPython_ScriptBox(void) +{ + PyObject *module; + PyObject *dict; + PyObject *scriptbox; + PyObject *pystr; + + /* Get globals() */ + /* These two should never fail */ + module = PyImport_AddModule("__main__"); + dict = PyModule_GetDict(module); + + scriptbox = PyDict_GetItemString(dict, "ScriptBox_instance"); + + if (!scriptbox) + { + warning("INTERNAL ERROR: ScriptBox_instance missing! Broken init.py?"); + return; + } + + pystr = PyObject_CallMethod(scriptbox, "run", ""); + + if (pystr) + { + /* If the return value is string use it as path */ + if (PyObject_TypeCheck(pystr, &PyString_Type)) + { + ExecFile(PyString_AsString(pystr)); + } + Py_DECREF(pystr); + } + else + { + /* Print the exception info */ + if (PyErr_Occurred()) + { + PyErr_Print(); + } + } +} + +bool idaapi IDAPython_Menu_Callback(void *ud) +{ + run((int)ud); + return true; +} + + +/* Initialize the Python environment */ +bool IDAPython_Init(void) +{ + char *options; + char tmp[MAXSTR+64]; + char *initpath; + bool result = 1; + + /* Already initialized? */ + if (initialized == 1) + { + return true; + } + + /* Check for the presence of essential files */ + initialized = 0; + + result &= CheckFile("idc.py"); + result &= CheckFile("init.py"); + result &= CheckFile("idaapi.py"); + result &= CheckFile("idautils.py"); + + if (!result) + { + return false; + } + + /* Start the interpreter */ + Py_Initialize(); + + if (!Py_IsInitialized()) + { + warning("IDAPython: Py_Initialize() failed"); + return false; + } + + /* Init the SWIG wrapper */ + init_idaapi(); + + sprintf(tmp, "IDAPYTHON_VERSION=(%d, %d, %d, '%s', %d)", \ + VER_MAJOR, + VER_MINOR, + VER_PATCH, + VER_STATUS, + VER_SERIAL); + + PyRun_SimpleString(tmp); + +#if IDP_INTERFACE_VERSION >= 75 + qmakepath(tmp, MAXSTR, idadir("python"), "init.py", NULL); +#elif IDP_INTERFACE_VERSION >= 69 + qmakepath(tmp, idadir("python"), "init.py", NULL); +#else + qmakepath(tmp, idadir(), "python", "init.py", NULL); +#endif + + /* Pull in the Python side of init */ + if (!ExecFile(tmp)) + { + warning("IDAPython: error executing init.py"); + return false; + } + +#ifdef ENABLE_PYTHON_PROFILING + PyEval_SetTrace(tracefunc, NULL); +#endif + + /* Batch-mode operation: */ + /* A script specified on the command line is run */ + options = (char *)get_plugin_options("IDAPython"); + + if (options) + { + IDAPython_RunScript(options); + } + + /* Add menu items for all the functions */ + /* Different paths are used for the GUI version */ + result = add_menu_item("File/IDC command...", "P~y~thon command...", + "Alt-8", SETMENU_APP, + (menu_item_callback_t *)IDAPython_Menu_Callback, + (void *)IDAPYTHON_RUNSTATEMENT); + + result = add_menu_item("File/Load file/IDC file...", "P~y~thon file...", + "Alt-9", SETMENU_APP, + (menu_item_callback_t *)IDAPython_Menu_Callback, + (void *)IDAPYTHON_RUNFILE); + + if (!result) + { + add_menu_item("File/IDC command...", "P~y~thon file...", + "Alt-9", SETMENU_APP, + (menu_item_callback_t *)IDAPython_Menu_Callback, + (void *)IDAPYTHON_RUNFILE); + } + + result = add_menu_item("View/Open subviews/Show strings", "Python S~c~ripts", + "Alt-7", SETMENU_APP, + (menu_item_callback_t *)IDAPython_Menu_Callback, + (void *)IDAPYTHON_SCRIPTBOX); + + if (!result) + { + add_menu_item("View/Open subviews/Problems", "Python S~c~ripts", + "Alt-7", SETMENU_APP, + (menu_item_callback_t *)IDAPython_Menu_Callback, + (void *)IDAPYTHON_SCRIPTBOX); + } + + initialized = 1; + + return true; +} + +/* Cleaning up Python */ +void IDAPython_Term(void) +{ + /* Remove the menu items before termination */ +#if 0 + // FIXME: This segfaults the Linux version. The non-existent items might cause this? + del_menu_item("File/Load file/Python file..."); + del_menu_item("File/Python file..."); + del_menu_item("File/Python command..."); + del_menu_item("View/Open subviews/Python Scripts"); +#endif + + /* Shut the interpreter down */ + Py_Finalize(); + + initialized = 0; +} + +/* Plugin init routine */ +int idaapi init(void) +{ + if (IDAPython_Init()) + { + return PLUGIN_KEEP; + } + else + { + return PLUGIN_SKIP; + } +} + +/* Plugin term routine */ +void idaapi term(void) +{ + IDAPython_Term(); +} + +/* Plugin hotkey entry point */ +void idaapi run(int arg) +{ + try + { + switch (arg) + { + case 0: + IDAPython_RunScript(NULL); + break; + ;; + case 1: + IDAPython_RunStatement(); + break; + ;; + case 2: + IDAPython_ScriptBox(); + break; + ;; + default: + warning("IDAPython: unknown plugin argument %d", arg); + break; + ;; + } + } + catch(...) + { + warning("Exception in Python interpreter. Reloading..."); + IDAPython_Term(); + IDAPython_Init(); + } +} + +//-------------------------------------------------------------------------- +// PLUGIN DESCRIPTION BLOCK +//-------------------------------------------------------------------------- +char comment[] = "IDAPython"; +char help[] = "IDA Python Plugin\n"; +char wanted_name[] = "IDAPython"; +char wanted_hotkey[] = "Alt-9"; + +extern "C" +{ +plugin_t PLUGIN = { + IDP_INTERFACE_VERSION, + 0, // plugin flags + init, // initialize + + term, // terminate. this pointer may be NULL. + + run, // invoke plugin + + comment, // long comment about the plugin + // it could appear in the status line + // or as a hint + + help, // multiline help about the plugin + + wanted_name, // the preferred short name of the plugin + wanted_hotkey // the preferred hotkey to run the plugin +}; +} diff --git a/python/idautils.py b/python/idautils.py new file mode 100644 index 0000000..721aa73 --- /dev/null +++ b/python/idautils.py @@ -0,0 +1,268 @@ +#------------------------------------------------------------ +# IDAPython - Python plugin for Interactive Disassembler Pro +# +# Copyright (c) 2004-2007 Gergely Erdelyi +# +# All rights reserved. +# +# For detailed copyright information see the file COPYING in +# the root of the distribution archive. +#------------------------------------------------------------ +""" +idautils.py - High level utility functions for IDA +""" +from idaapi import * + +def refs(ea, funcfirst, funcnext): + """ + Generic reference collector - INTERNAL USE ONLY. + """ + reflist = [] + + ref = funcfirst(ea) + + if ref != BADADDR: + reflist.append(ref) + + while 1: + ref = funcnext(ea, ref) + + if ref == BADADDR: + break + else: + reflist.append(ref) + + return reflist + + +def CodeRefsTo(ea, flow): + """ + Get a list of code references to 'ea' + + @param ea: Target address + @param flow: Follow normal code flow or not + @type flow: Boolean (0/1, False/True) + + @return: list of references (may be empty list) + + Example:: + + for ref in CodeRefsTo(ScreenEA(), 1): + print ref + """ + if flow == 1: + return refs(ea, get_first_cref_to, get_next_cref_to) + else: + return refs(ea, get_first_fcref_to, get_next_fcref_to) + + +def CodeRefsFrom(ea, flow): + """ + Get a list of code references from 'ea' + + @param ea: Target address + @param flow: Follow normal code flow or not + @type flow: Boolean (0/1, False/True) + + @return: list of references (may be empty list) + + Example:: + + for ref in CodeRefsFrom(ScreenEA(), 1): + print ref + """ + if flow == 1: + return refs(ea, get_first_cref_from, get_next_cref_from) + else: + return refs(ea, get_first_fcref_from, get_next_fcref_from) + + +def DataRefsTo(ea): + """ + Get a list of data references to 'ea' + + @param ea: Target address + + @return: list of references (may be empty list) + + Example:: + + for ref in DataRefsTo(ScreenEA(), 1): + print ref + """ + return refs(ea, get_first_dref_to, get_next_dref_to) + + +def DataRefsFrom(ea): + """ + Get a list of data references from 'ea' + + @param ea: Target address + + @return: list of references (may be empty list) + + Example:: + + for ref in DataRefsFrom(ScreenEA(), 1): + print ref + """ + return refs(ea, get_first_dref_from, get_next_dref_from) + + +def Heads(start, end): + """ + Get a list of heads (instructions or data) + + @param start: start address (this one is always included) + @param end: end address + + @return: list of heads between start and end + """ + headlist = [] + headlist.append(start) + + ea = start + + while 1: + ea = next_head(ea, end) + + if ea == BADADDR: + break + else: + headlist.append(ea) + + return headlist + + +def Functions(start, end): + """ + Get a list of functions + + @param start: start address + @param end: end address + + @return: list of heads between start and end + + @note: The last function that starts before 'end' is included even + if it extends beyond 'end'. + """ + startaddr = start + endaddr = end + + funclist = [] + + func = get_func(start) + + if func: + funclist.append(func.startEA) + + ea = start + + while 1: + func = get_next_func(ea) + + if not func: break + + if func.startEA < end: + funclist.append(func.startEA) + ea = func.startEA + else: + break + + return funclist + + +def Segments(): + """ + Get list of segments (sections) in the binary image + + @return: List of segment start addresses. + """ + seglist = [] + + for n in range(get_segm_qty()): + seg = getnseg(n) + + if not seg: + break + else: + seglist.append(seg.startEA) + + return seglist + + +def GetDataList(ea, count, itemsize=1): + """ + Get data list - INTERNAL USE ONLY + """ + getdata = None + + if itemsize == 1: + getdata = get_byte + if itemsize == 2: + getdata = get_word + if itemsize == 4: + getdata = get_dword + + if getdata == None: + raise ValueError, "Invalid data size! Must be 1, 2 or 4" + + list = [] + + for offs in range(count): + list.append(getdata(ea)) + ea = ea + itemsize + + return list + + +def PutDataList(ea, list, itemsize=1): + """ + Put data list - INTERNAL USE ONLY + """ + putdata = None + + if itemsize == 1: + putdata = patch_byte + if itemsize == 2: + putdata = patch_word + if itemsize == 4: + putdata = patch_dword + + if putdata == None: + raise ValueError, "Invalid data size! Must be 1, 2 or 4" + + for val in list: + putdata(ea, val) + ea = ea + itemsize + + +def MapDataList(ea, length, func, wordsize=1): + """ + Map through a list of data words in the database + + @param ea: start address + @param length: number of words to map + @param func: mapping function + @param wordsize: size of words to map [default: 1 byte] + + @return: None + """ + PutDataList(ea, map(func, GetDataList(ea, length, wordsize)), wordsize) + + +def GetInputFileMD5(): + """ + Return the MD5 hash of the input binary file + + @return: MD5 string or None on error + """ + ua=ucharArray(16) + if retrieve_input_file_md5(ua.cast()): + md5str="" + for i in range(16): + md5str += "%02x" % ua[i] + return md5str + else: + return None + diff --git a/python/idc.py b/python/idc.py new file mode 100644 index 0000000..823382d --- /dev/null +++ b/python/idc.py @@ -0,0 +1,6123 @@ +#!/usr/bin/env python +#------------------------------------------------------------ +# IDAPython - Python plugin for Interactive Disassembler Pro +# +# Original IDC.IDC: +# Copyright (c) 1990-2007 Ilfak Guilfanov +# +# Python conversion: +# Copyright (c) 2004-2007 Gergely Erdelyi +# +# All rights reserved. +# +# For detailed copyright information see the file COPYING in +# the root of the distribution archive. +#------------------------------------------------------------ +# idc.py - IDC compatibility module +#------------------------------------------------------------ +""" +IDC compatibility module + +This file contains IDA built-in function declarations and internal bit +definitions. Each byte of the program has 32-bit flags (low 8 bits keep +the byte value). These 32 bits are used in GetFlags/SetFlags functions. +You may freely examine these bits using GetFlags() but the use of the +SetFlags() function is strongly discouraged. + +This file is subject to change without any notice. +Future versions of IDA may use other definitions. +""" +try: + import idaapi +except: + print "Could not import idaapi. Running in 'pydoc mode'." + +import os, struct, re + +class DeprecatedIDCError(Exception): + """ + Exception for deprecated function calls + """ + def __init__(self, val): + self.var = val + + def __str__(self): + return self.val + + +def _IDC_GetAttr(object, map, attroffs): + """ + Internal function to generically get object attributes + Do not use unless you know what you are doing + """ + if attroffs in map and hasattr(object, map[attroffs]): + return getattr(object, map[attroffs]) + else: + str = "attribute with offset %d not found, check the offset and report the problem" % attroffs + raise KeyError, str + + +def _IDC_SetAttr(object, map, attroffs, value): + """ + Internal function to generically set object attributes + Do not use unless you know what you are doing + """ + if attroffs in map and hasattr(object, map[attroffs]): + return setattr(object, map[attroffs], value) + else: + str = "attribute with offset %d not found, check the offset and report the problem" % attroffs + raise KeyError, str + + +BADADDR = idaapi.BADADDR # Not allowed address value +BADSEL = idaapi.BADSEL # Not allowed selector value/number +MAXADDR = idaapi.MAXADDR + +# +# Flag bit definitions (for GetFlags()) +# +MS_VAL = idaapi.MS_VAL # Mask for byte value +FF_IVL = idaapi.FF_IVL # Byte has value ? + +# Do flags contain byte value? (i.e. has the byte a value?) +# if not, the byte is uninitialized. + +def hasValue(F): return ((F & FF_IVL) != 0) # any defined value? + +# Get byte value from flags +# Get value of byte provided that the byte is initialized. +# This macro works ok only for 8-bit byte machines. + +def byteValue(F): return (F & MS_VAL) # quick replacement for Byte() + +# Is the byte initialized? + +def isLoaded(ea): hasValue(GetFlags(ea)) # any defined value? + +MS_CLS = idaapi.MS_CLS # Mask for typing +FF_CODE = idaapi.FF_CODE # Code ? +FF_DATA = idaapi.FF_DATA # Data ? +FF_TAIL = idaapi.FF_TAIL # Tail ? +FF_UNK = idaapi.FF_UNK # Unknown ? + +def isCode(F): return ((F & MS_CLS) == FF_CODE) # is code byte? +def isData(F): return ((F & MS_CLS) == FF_DATA) # is data byte? +def isTail(F): return ((F & MS_CLS) == FF_TAIL) # is tail byte? +def isUnknown(F): return ((F & MS_CLS) == FF_UNK) # is unexplored byte? +def isHead(F): return ((F & FF_DATA) != 0) # is start of code/data? + +# +# Common bits +# +MS_COMM = idaapi.MS_COMM # Mask of common bits +FF_COMM = idaapi.FF_COMM # Has comment? +FF_REF = idaapi.FF_REF # has references? +FF_LINE = idaapi.FF_LINE # Has next or prev cmt lines ? +FF_NAME = idaapi.FF_NAME # Has user-defined name ? +FF_LABL = idaapi.FF_LABL # Has dummy name? +FF_FLOW = idaapi.FF_FLOW # Exec flow from prev instruction? +FF_VAR = idaapi.FF_VAR # Is byte variable ? +FF_ANYNAME = FF_LABL | FF_NAME + +def isFlow(F): return ((F & FF_FLOW) != 0) +def isVar(F): return ((F & FF_VAR ) != 0) +def isExtra(F): return ((F & FF_LINE) != 0) +def isRef(F): return ((F & FF_REF) != 0) +def hasName(F): return ((F & FF_NAME) != 0) +def hasUserName(F): return ((F & FF_ANYNAME) == FF_NAME) + +MS_0TYPE = idaapi.MS_0TYPE # Mask for 1st arg typing +FF_0VOID = idaapi.FF_0VOID # Void (unknown)? +FF_0NUMH = idaapi.FF_0NUMH # Hexadecimal number? +FF_0NUMD = idaapi.FF_0NUMD # Decimal number? +FF_0CHAR = idaapi.FF_0CHAR # Char ('x')? +FF_0SEG = idaapi.FF_0SEG # Segment? +FF_0OFF = idaapi.FF_0OFF # Offset? +FF_0NUMB = idaapi.FF_0NUMB # Binary number? +FF_0NUMO = idaapi.FF_0NUMO # Octal number? +FF_0ENUM = idaapi.FF_0ENUM # Enumeration? +FF_0FOP = idaapi.FF_0FOP # Forced operand? +FF_0STRO = idaapi.FF_0STRO # Struct offset? +FF_0STK = idaapi.FF_0STK # Stack variable? + +MS_1TYPE = idaapi.MS_1TYPE # Mask for 2nd arg typing +FF_1VOID = idaapi.FF_1VOID # Void (unknown)? +FF_1NUMH = idaapi.FF_1NUMH # Hexadecimal number? +FF_1NUMD = idaapi.FF_1NUMD # Decimal number? +FF_1CHAR = idaapi.FF_1CHAR # Char ('x')? +FF_1SEG = idaapi.FF_1SEG # Segment? +FF_1OFF = idaapi.FF_1OFF # Offset? +FF_1NUMB = idaapi.FF_1NUMB # Binary number? +FF_1NUMO = idaapi.FF_1NUMO # Octal number? +FF_1ENUM = idaapi.FF_1ENUM # Enumeration? +FF_1FOP = idaapi.FF_1FOP # Forced operand? +FF_1STRO = idaapi.FF_1STRO # Struct offset? +FF_1STK = idaapi.FF_1STK # Stack variable? + +# The following macros answer questions like +# 'is the 1st (or 2nd) operand of instruction or data of the given type'? +# Please note that data items use only the 1st operand type (is...0) + +def isDefArg0(F): return ((F & MS_0TYPE) != FF_0VOID) +def isDefArg1(F): return ((F & MS_1TYPE) != FF_1VOID) +def isDec0(F): return ((F & MS_0TYPE) == FF_0NUMD) +def isDec1(F): return ((F & MS_1TYPE) == FF_1NUMD) +def isHex0(F): return ((F & MS_0TYPE) == FF_0NUMH) +def isHex1(F): return ((F & MS_1TYPE) == FF_1NUMH) +def isOct0(F): return ((F & MS_0TYPE) == FF_0NUMO) +def isOct1(F): return ((F & MS_1TYPE) == FF_1NUMO) +def isBin0(F): return ((F & MS_0TYPE) == FF_0NUMB) +def isBin1(F): return ((F & MS_1TYPE) == FF_1NUMB) +def isOff0(F): return ((F & MS_0TYPE) == FF_0OFF) +def isOff1(F): return ((F & MS_1TYPE) == FF_1OFF) +def isChar0(F): return ((F & MS_0TYPE) == FF_0CHAR) +def isChar1(F): return ((F & MS_1TYPE) == FF_1CHAR) +def isSeg0(F): return ((F & MS_0TYPE) == FF_0SEG) +def isSeg1(F): return ((F & MS_1TYPE) == FF_1SEG) +def isEnum0(F): return ((F & MS_0TYPE) == FF_0ENUM) +def isEnum1(F): return ((F & MS_1TYPE) == FF_1ENUM) +def isFop0(F): return ((F & MS_0TYPE) == FF_0FOP) +def isFop1(F): return ((F & MS_1TYPE) == FF_1FOP) +def isStroff0(F): return ((F & MS_0TYPE) == FF_0STRO) +def isStroff1(F): return ((F & MS_1TYPE) == FF_1STRO) +def isStkvar0(F): return ((F & MS_0TYPE) == FF_0STK) +def isStkvar1(F): return ((F & MS_1TYPE) == FF_1STK) + +# +# Bits for DATA bytes +# +DT_TYPE = idaapi.DT_TYPE # Mask for DATA typing + +FF_BYTE = idaapi.FF_BYTE # byte +FF_WORD = idaapi.FF_WORD # word +FF_DWRD = idaapi.FF_DWRD # dword +FF_QWRD = idaapi.FF_QWRD # qword +FF_TBYT = idaapi.FF_TBYT # tbyte +FF_ASCI = idaapi.FF_ASCI # ASCII ? +FF_STRU = idaapi.FF_STRU # Struct ? +FF_OWRD = idaapi.FF_OWRD # octaword (16 bytes) +FF_FLOAT = idaapi.FF_FLOAT # float +FF_DOUBLE = idaapi.FF_DOUBLE # double +FF_PACKREAL = idaapi.FF_PACKREAL # packed decimal real +FF_ALIGN = idaapi.FF_ALIGN # alignment directive + +# +# Bits for CODE bytes +# +MS_CODE = idaapi.MS_CODE +FF_FUNC = idaapi.FF_FUNC # function start? +FF_IMMD = idaapi.FF_IMMD # Has Immediate value ? +FF_JUMP = idaapi.FF_JUMP # Has jump table + +# +# Loader flags +# +NEF_SEGS = idaapi.NEF_SEGS # Create segments +NEF_RSCS = idaapi.NEF_RSCS # Load resources +NEF_NAME = idaapi.NEF_NAME # Rename entries +NEF_MAN = idaapi.NEF_MAN # Manual load +NEF_FILL = idaapi.NEF_FILL # Fill segment gaps +NEF_IMPS = idaapi.NEF_IMPS # Create imports section +NEF_TIGHT = idaapi.NEF_TIGHT # Don't align segments (OMF) +NEF_FIRST = idaapi.NEF_FIRST # This is the first file loaded +NEF_CODE = idaapi.NEF_CODE # for load_binary_file: +NEF_RELOAD = idaapi.NEF_RELOAD # reload the file at the same place: +NEF_FLAT = idaapi.NEF_FLAT # Autocreate FLAT group (PE) + +# List of built-in functions +# -------------------------- +# +# The following conventions are used in this list: +# 'ea' is a linear address +# 'success' is 0 if a function failed, 1 otherwise +# 'void' means that function returns no meaningful value (always 0) +# +# All function parameter conversions are made automatically. +# +# ---------------------------------------------------------------------------- +# M I S C E L L A N E O U S +# ---------------------------------------------------------------------------- +def MK_FP(seg, off): + """ + Return value of expression: ((seg<<4) + off) + """ + return (seg << 4) + off + +def form(format, *args): + raise DeprecatedIDCError, "form() is deprecated. Use python string operations instead." + +def substr(str,x1,x2): + raise DeprecatedIDCError, "substr() is deprecated. Use python string operations instead." + +def strstr(str, substr): + raise DeprecatedIDCError, "strstr() is deprecated. Use python string operations instead." + +def strlen(str): + raise DeprecatedIDCError, "strlen() is deprecated. Use python string operations instead." + +def xtol(str): + raise DeprecatedIDCError, "xtol() is deprecated. Use python long() instead." + + +def atoa(ea): + """ + Convert address value to a string + Return address in the form 'seg000:1234' + (the same as in line prefixes) + + @param ea: address to format + + FIXME: unimplemented + """ + segname = SegName(ea) + + if segname == "": + segname = "0" + + return "%s:%X" % (segname, ea) + + +def ltoa(n, radix): + raise DeprecatedIDCError, "ltoa() is deprecated. Use python string operations instead." + +def atol(str): + raise DeprecatedIDCError, "atol() is deprecated. Use python long() instead." + + +def rotate_left(value, count, nbits, offset): + """ + Rotate a value to the left (or right) + + @param x: value to rotate + @param count: number of times to rotate. negative counter means + rotate to the right + @param nbits: number of bits to rotate + @param offset: offset of the first bit to rotate + + @return: the value with the specified field rotated + all other bits are not modified + + FIXME: unimplemented + """ + raise NotImplementedError + + +def AddHotkey(hotkey, idcfunc): + """ + Add hotkey for IDC function + + @param hotkey: hotkey name ('a', "Alt-A", etc) + @param idcfunc: IDC function name + + @note: GUI version doesn't support hotkeys + + @return: None + """ + return idaapi.add_idc_hotkey(hotkey, idcfunc) + + +# AddHotkey return codes +IDCHK_OK = 0 # ok +IDCHK_ARG = -1 # bad argument(s) +IDCHK_KEY = -2 # bad hotkey name +IDCHK_MAX = -3 # too many IDC hotkeys + + +def DelHotkey(hotkey): + """ + Delete IDC function hotkey + + @param hotkey: hotkey code to delete + """ + return idaapi.del_idc_hotkey(hotkey) + + +def Jump(ea): + """ + Move cursor to the specifed linear address + + @param ea: linear address + """ + return idaapi.jumpto(ea) + + +def Wait(): + """ + Process all entries in the autoanalysis queue + Wait for the end of autoanalysis + + @note: This function will suspend execution of the calling script + till the autoanalysis queue is empty. + """ + return idaapi.autoWait() + + +def Compile(filename): + raise DeprecatedIDCError, "Compile() is for IDC and unsupported." + + +def Exit(code): + """ + Stop execution of IDC program, close the database and exit to OS + + @param code: code to exit with. + + @return: - + """ + idaapi.qexit(code) + + +def Exec(command): + """ + Execute an OS command. + + @param command: command line to execute + + @return: error code from OS + + @note: + IDA will wait for the started program to finish. + In order to start the command in parallel, use OS methods. + For example, you may start another program in parallel using + "start" command. + """ + return os.system(command) + + +def RunPlugin(name, arg): + """ + Load and run a plugin + + @param name: The plugin name is a short plugin name without an extension + @param arg: integer argument + + @return: 0 if could not load the plugin, 1 if ok + """ + return idaapi.load_and_run_plugin(name, arg) + + +def ApplySig(name): + """ + Load (plan to apply) a FLIRT signature file + + @param name: signature name without path and extension + + @return: 0 if could not load the signature file, !=0 otherwise + """ + return idaapi.plan_to_apply_idasgn(name) + + +#---------------------------------------------------------------------------- +# C H A N G E P R O G R A M R E P R E S E N T A T I O N +#---------------------------------------------------------------------------- + + +def DeleteAll(): + """ + Delete all segments, instructions, comments, i.e. everything + except values of bytes. + """ + ea = idaapi.cvar.inf.minEA + + # Brute-force nuke all info from all the heads + while ea != BADADDR and ea <= idaapi.cvar.inf.maxEA: + idaapi.del_local_name(ea) + idaapi.del_global_name(ea) + func = idaapi.get_func(ea) + if func: + idaapi.del_func_cmt(func, False) + idaapi.del_func_cmt(func, True) + idaapi.del_func(ea) + idaapi.del_hidden_area(ea) + seg = idaapi.getseg(ea) + if seg: + idaapi.del_segment_cmt(seg, False) + idaapi.del_segment_cmt(seg, True) + idaapi.del_segm(ea, idaapi.SEGDEL_KEEP | idaapi.SEGDEL_SILENT) + + ea = idaapi.next_head(ea, idaapi.cvar.inf.maxEA) + + +def MakeCode(ea): + """ + Create an instruction at the specified address + + @param ea: linear address + + @return: 0 - can not create an instruction (no such opcode, the instruction + would overlap with existing items, etc) otherwise returns length of the + instruction in bytes + """ + return idaapi.ua_code(ea) + + +def AnalyzeArea(sEA, eEA): + """ + Perform full analysis of the area + + @param sEA: starting linear address + @param eEA: ending linear address (excluded) + + @return: 1-ok, 0-Ctrl-Break was pressed. + """ + return idaapi.analyze_area(sEA, eEA) + + +def MakeNameEx(ea, name, flags): + """ + Rename an address + + @param ea: linear address + @param name: new name of address. If name == "", then delete old name + @param flags: combination of SN_... constants + + @return: 1-ok, 0-failure + """ + return idaapi.set_name(ea, name, flags) + +SN_CHECK = idaapi.SN_CHECK # Fail if the name contains invalid + # characters + # If this bit is clear, all invalid chars + # (those !is_ident_char()) will be replaced + # by SubstChar (usually '_') + # List of valid characters is defined in + # ida.cfg +SN_NOCHECK = idaapi.SN_NOCHECK # Replace invalid chars with SubstChar +SN_PUBLIC = idaapi.SN_PUBLIC # if set, make name public +SN_NON_PUBLIC = idaapi.SN_NON_PUBLIC # if set, make name non-public +SN_WEAK = idaapi.SN_WEAK # if set, make name weak +SN_NON_WEAK = idaapi.SN_NON_WEAK # if set, make name non-weak +SN_AUTO = idaapi.SN_AUTO # if set, make name autogenerated +SN_NON_AUTO = idaapi.SN_NON_AUTO # if set, make name non-autogenerated +SN_NOLIST = idaapi.SN_NOLIST # if set, exclude name from the list + # if not set, then include the name into + # the list (however, if other bits are set, + # the name might be immediately excluded + # from the list) +SN_NOWARN = idaapi.SN_NOWARN # don't display a warning if failed +SN_LOCAL = idaapi.SN_LOCAL # create local name. a function should exist. + # local names can't be public or weak. + # also they are not included into the list + # of names they can't have dummy prefixes + +def MakeComm(ea, comment): + """ + Set an indented regular comment of an item + + @param ea: linear address + @param comment: comment string + + @return: None + """ + return idaapi.set_cmt(ea, comment, 0) + + +def MakeRptCmt(ea, comment): + """ + Set an indented repeatable comment of an item + + @param ea: linear address + @param comment: comment string + + @return: None + """ + return idaapi.set_cmt(ea, comment, 1) + + +def MakeArray(ea, nitems): + """ + Create an array. + + @param ea: linear address + @param nitems: size of array in items + + @note: This function will create an array of the items with the same type as + the type of the item at 'ea'. If the byte at 'ea' is undefined, then + this function will create an array of bytes. + """ + flags = idaapi.getFlags(ea) + + if idaapi.isUnknown(flags): + flags = idaapi.FF_BYTE + + if idaapi.isStruct(flags): + ti = idaapi.typeinfo_t() + assert idaapi.get_typeinfo(ea, 0, flags, ti), "get_typeinfo() failed" + itemsize = idaapi.get_data_elsize(ea, flags, ti) + tid = ti.tid + else: + itemsize = idaapi.get_item_size(ea) + tid = BADADDR + + return idaapi.do_data_ex(ea, flags, itemsize*nitems, tid) + + +def MakeStr(ea, endea): + """ + Create a string. + + This function creates a string (the string type is determined by the + value of GetLongPrm(INF_STRTYPE)) + + @param ea: linear address + @param endea: ending address of the string (excluded) + if endea == BADADDR, then length of string will be calculated + by the kernel + + @return: 1-ok, 0-failure + + @note: The type of an existing string is returned by GetStringType() + """ + return idaapi.make_ascii_string(ea, endea - ea, GetLongPrm(INF_STRTYPE)) + + +def MakeByte(ea): + """ + Convert the current item to a byte + + @param ea: linear address + + @return: 1-ok, 0-failure + """ + return idaapi.doByte(ea, 1) + + +def MakeWord(ea): + """ + Convert the current item to a word (2 bytes) + + @param ea: linear address + + @return: 1-ok, 0-failure + """ + return idaapi.doWord(ea, 2) + + +def MakeDword(ea): + """ + Convert the current item to a double word (4 bytes) + + @param ea: linear address + + @return: 1-ok, 0-failure + """ + return idaapi.doDwrd(ea, 4) + + +def MakeQword(ea): + """ + Convert the current item to a quadro word (8 bytes) + + @param ea: linear address + + @return: 1-ok, 0-failure + """ + return idaapi.doQwrd(ea, 8) + + +def MakeOword(ea): + """ + Convert the current item to a octa word (16 bytes) + + @param ea: linear address + + @return: 1-ok, 0-failure + """ + return idaapi.doOwrd(ea, 16) + + +def MakeFloat(ea): + """ + Convert the current item to a floating point (4 bytes) + + @param ea: linear address + + @return: 1-ok, 0-failure + """ + return idaapi.doFloat(ea, 4) + + +def MakeDouble(ea): + """ + Convert the current item to a double floating point (8 bytes) + + @param ea: linear address + + @return: 1-ok, 0-failure + """ + return idaapi.doDouble(ea, 8) + + +def MakePackReal(ea): + """ + Convert the current item to a packed real (10 or 12 bytes) + + @param ea: linear address + + @return: 1-ok, 0-failure + """ + return idaapi.doPackReal(ea, idaapi.cvar.ph.tbyte_size) + + +def MakeTbyte(ea): + """ + Convert the current item to a tbyte (10 or 12 bytes) + + @param ea: linear address + + @return: 1-ok, 0-failure + """ + return idaapi.doTbyt(ea, idaapi.cvar.ph.tbyte_size) + + +def MakeStructEx(ea, size, strname): + """ + Convert the current item to a structure instance + + @param ea: linear address + @param size: structure size in bytes. -1 means that the size + will be calculated automatically + @param strname: name of a structure type + + @return: 1-ok, 0-failure + """ + strid = idaapi.get_struc_id(strname) + + # FIXME: This should be changed to BADNODE + if strid == 0xFFFFFFFF: + return False + + if size == -1: + size = idaapi.get_struc_size(strid) + + return idaapi.doStruct(ea, size, strid) + + +def MakeAlign(ea, count, align): + """ + Convert the current item to an alignment directive + + @param ea: linear address + @param count: number of bytes to convert + @param align: 0 or 1..32 + if it is 0, the correct alignment will be calculated + by the kernel + + @return: 1-ok, 0-failure + """ + return idaapi.doAlign(ea, count, align) + + +def MakeLocal(start, end, location, name): + """ + Create a local variable + + @param start: start of address range for the local variable + @param end: end of address range for the local variable + @param location: the variable location in the "[bp+xx]" form where xx is + a number. The location can also be specified as a + register name. + @param name: name of the local variable + + @return: 1-ok, 0-failure + + @note: For the stack variables the end address is ignored. + If there is no function at 'start' then this function. + will fail. + """ + func = idaapi.get_func(start) + + if not func: + return 0 + + # Find out if location is in the [bp+xx] form + r = re.compile("\[([a-z]+)([-+][0-9a-fx]+)", re.IGNORECASE) + m = r.match(location) + + if m: + # Location in the form of [bp+xx] + register = idaapi.str2reg(m.group(1)) + offset = int(m.group(2), 0) + frame = idaapi.get_frame(func) + + print register, frame + + if register == -1 or not frame: + return 0 + + offset += func.frsize + + member = idaapi.get_member(frame, offset) + + if member: + # Member already exists, rename it + if idaapi.set_member_name(frame, offset, name): + return 1 + else: + return 0 + else: + # No member at the offset, create a new one + if idaapi.add_struc_member(frame, + name, + offset, + idaapi.byteflag(), + None, 1) == 0: + return 1 + else: + return 0 + else: + # Location as simple register name + return idaapi.add_regvar(func, start, end, location, name, None) + + +def MakeUnkn(ea, flags): + """ + Convert the current item to an explored item + + @param ea: linear address + @param flags: combination of DOUNK_* constants + + @return: None + """ + return idaapi.do_unknown(ea, flags) + + +def MakeUnknown(ea, size, flags): + """ + Convert the current item to an explored item + + @param ea: linear address + @param size: size of the range to undefine (for MakeUnknown) + @param flags: combination of DOUNK_* constants + + @return: None + """ + return idaapi.do_unknown_range(ea, size, flags) + + +DOUNK_SIMPLE = idaapi.DOUNK_SIMPLE # simply undefine the specified item +DOUNK_EXPAND = idaapi.DOUNK_EXPAND # propogate undefined items, for example + # if removing an instruction removes all + # references to the next instruction, then + # plan to convert to unexplored the next + # instruction too. +DOUNK_DELNAMES = idaapi.DOUNK_DELNAMES # delete any names at the specified address(es) + + +def OpBinary(ea, n): + """ + Convert an operand of the item (instruction or data) to a binary number + + @param ea: linear address + @param n: number of operand + - 0 - the first operand + - 1 - the second, third and all other operands + - -1 - all operands + + @return: 1-ok, 0-failure + + @note: the data items use only the type of the first operand + """ + return idaapi.op_bin(ea, n) + + +def OpOctal(ea, n): + """ + Convert an operand of the item (instruction or data) to an octal number + + @param ea: linear address + @param n: number of operand + - 0 - the first operand + - 1 - the second, third and all other operands + - -1 - all operands + """ + return idaapi.op_oct(ea, n) + + +def OpDecimal(ea, n): + """ + Convert an operand of the item (instruction or data) to a decimal number + + @param ea: linear address + @param n: number of operand + - 0 - the first operand + - 1 - the second, third and all other operands + - -1 - all operands + """ + return idaapi.op_dec(ea, n) + + +def OpHex(ea, n): + """ + Convert an operand of the item (instruction or data) to a hexadecimal number + + @param ea: linear address + @param n: number of operand + - 0 - the first operand + - 1 - the second, third and all other operands + - -1 - all operands + """ + return idaapi.op_hex(ea, n) + + +def OpChr(ea, n): + """ + @param ea: linear address + @param n: number of operand + - 0 - the first operand + - 1 - the second, third and all other operands + - -1 - all operands + """ + return idaapi.op_chr(ea, n) + + +def OpOff(ea, n, base): + """ + Convert operand to an offset + (for the explanations of 'ea' and 'n' please see OpBinary()) + + Example: + ======== + + seg000:2000 dw 1234h + + and there is a segment at paragraph 0x1000 and there is a data item + within the segment at 0x1234: + + seg000:1234 MyString db 'Hello, world!',0 + + Then you need to specify a linear address of the segment base to + create a proper offset: + + OpOffset(["seg000",0x2000],0,0x10000); + + and you will have: + + seg000:2000 dw offset MyString + + Motorola 680x0 processor have a concept of "outer offsets". + If you want to create an outer offset, you need to combine number + of the operand with the following bit: + + Please note that the outer offsets are meaningful only for + Motorola 680x0. + + @param ea: linear address + @param n: number of operand + - 0 - the first operand + - 1 - the second, third and all other operands + - -1 - all operands + @param base: base of the offset as a linear address + If base == BADADDR then the current operand becomes non-offset + """ + return idaapi.set_offset(ea, n, base) + + +OPND_OUTER = idaapi.OPND_OUTER # outer offset base + + +def OpOffEx(ea, n, reftype, target, base, tdelta): + """ + Convert operand to a complex offset expression + This is a more powerful version of OpOff() function. + It allows to explicitly specify the reference type (off8,off16, etc) + and the expression target with a possible target delta. + The complex expressions are represented by IDA in the following form: + + target + tdelta - base + + If the target is not present, then it will be calculated using + + target = operand_value - tdelta + base + + The target must be present for LOW.. and HIGH.. reference types + + @param ea: linear address of the instruction/data + @param n: number of operand to convert (the same as in OpOff) + @param reftype: one of REF_... constants + @param target: an explicitly specified expression target. if you don't + want to specify it, use -1. Please note that LOW... and + HIGH... reference type requre the target. + @param base: the offset base (a linear address) + @param tdelta: a displacement from the target which will be displayed + in the expression. + + @return: success (boolean) + """ + return idaapi.op_offset(ea, n, reftype, target, base, tdelta) + + +REF_OFF8 = idaapi.REF_OFF8 # 8bit full offset +REF_OFF16 = idaapi.REF_OFF16 # 16bit full offset +REF_OFF32 = idaapi.REF_OFF32 # 32bit full offset +REF_LOW8 = idaapi.REF_LOW8 # low 8bits of 16bit offset +REF_LOW16 = idaapi.REF_LOW16 # low 16bits of 32bit offset +REF_HIGH8 = idaapi.REF_HIGH8 # high 8bits of 16bit offset +REF_HIGH16 = idaapi.REF_HIGH16 # high 16bits of 32bit offset +REF_VHIGH = idaapi.REF_VHIGH # high ph.high_fixup_bits of 32bit offset (processor dependent) +REF_VLOW = idaapi.REF_VLOW # low (32-ph.high_fixup_bits) of 32bit offset (processor dependent) +REF_OFF64 = idaapi.REF_OFF64 # 64bit full offset +REFINFO_RVA = 0x10 # based reference (rva) +REFINFO_PASTEND = 0x20 # reference past an item it may point to an nonexistitng + # do not destroy alignment dirs +REFINFO_NOBASE = 0x80 # offset base is a number + # that base have be any value + # nb: base xrefs are created only if base + # points to the middle of a segment + + +def OpSeg(ea, n): + """ + Convert operand to a segment expression + + @param ea: linear address + @param n: number of operand + - 0 - the first operand + - 1 - the second, third and all other operands + - -1 - all operands + """ + return idaapi.op_seg(ea, n) + + +def OpNumber(ea, n): + """ + Convert operand to a number (with default number base, radix) + + @param ea: linear address + @param n: number of operand + - 0 - the first operand + - 1 - the second, third and all other operands + - -1 - all operands + """ + return idaapi.op_num(ea, n) + + +def OpAlt(ea, n, str): + """ + Specify operand represenation manually. + + @param ea: linear address + @param n: number of operand + - 0 - the first operand + - 1 - the second, third and all other operands + - -1 - all operands + @param str: a string represenation of the operand + + @note: IDA will not check the specified operand, it will simply display + it instead of the orginal representation of the operand. + """ + return idaapi.set_forced_operand(ea, n, str) + + +def OpSign(ea, n): + """ + Change sign of the operand + + @param ea: linear address + @param n: number of operand + - 0 - the first operand + - 1 - the second, third and all other operands + - -1 - all operands + """ + return idaapi.toggle_signness(ea, n) + + +def OpNot(ea, n): + """ + Toggle the bitwise not operator for the operand + + @param ea: linear address + @param n: number of operand + - 0 - the first operand + - 1 - the second, third and all other operands + - -1 - all operands + """ + idaapi.toggle_bnot(ea, n) + return True + + +def OpEnumEx(ea, n, enumid, serial): + """ + Convert operand to a symbolic constant + + @param ea: linear address + @param n: number of operand + - 0 - the first operand + - 1 - the second, third and all other operands + - -1 - all operands + @param enumid: id of enumeration type + @param serial: serial number of the constant in the enumeration + The serial numbers are used if there are more than + one symbolic constant with the same value in the + enumeration. In this case the first defined constant + get the serial number 0, then second 1, etc. + There could be 256 symbolic constants with the same + value in the enumeration. + """ + return idaapi.op_enum(ea, n, enumid, serial) + + +def OpStroffEx(ea, n, strid, delta): + """ + Convert operand to an offset in a structure + + @param ea: linear address + @param n: number of operand + - 0 - the first operand + - 1 - the second, third and all other operands + - -1 - all operands + @param strid: id of a structure type + @param delta: struct offset delta. usually 0. denotes the difference + between the structure base and the pointer into the structure. + + """ + path = idaapi.tidArray(1) + path[0] = strid + return idaapi.op_stroff(ea, n, path.cast(), 1, delta) + + +def OpStkvar(ea, n): + """ + Convert operand to a stack variable + + @param ea: linear address + @param n: number of operand + - 0 - the first operand + - 1 - the second, third and all other operands + - -1 - all operands + """ + return idaapi.op_stkvar(ea, n) + + +def OpHigh(ea, n, target): + """ + Convert operand to a high offset + High offset is the upper 16bits of an offset. + This type is used by TMS320C6 processors (and probably by other + RISC processors too) + + @param ea: linear address + @param n: number of operand + - 0 - the first operand + - 1 - the second, third and all other operands + - -1 - all operands + @param target: the full value (all 32bits) of the offset + """ + return idaapi.op_offset(ea, n, idaapi.REF_HIGH16, target) + + +def MakeVar(ea): + """ + Mark the location as "variable" + + @param ea: address to mark + + @return: None + + @note: All that IDA does is to mark the location as "variable". + Nothing else, no additional analysis is performed. + This function may disappear in the future. + """ + idaapi.doVar(ea, 1) + + +def ExtLinA(ea, n, line): + """ + Specify an additional line to display before the generated ones. + + @param ea: linear address + @param n: number of anterior additioal line (0..MAX_ITEM_LINES) + @param line: the line to display + + @return: None + + @note: IDA displays additional lines from number 0 up to the first unexisting + additional line. So, if you specify additional line #150 and there is no + additional line #149, your line will not be displayed. MAX_ITEM_LINES is + defined in IDA.CFG + """ + idaapi.ExtraUpdate(ea, line, idaapi.E_PREV + n) + + +def ExtLinB(ea, n, line): + """ + Specify an additional line to display after the generated ones. + + @param ea: linear address + @param n: number of posterior additioal line (0..MAX_ITEM_LINES) + @param line: the line to display + + @return: None + + @note: IDA displays additional lines from number 0 up to the first + unexisting additional line. So, if you specify additional line #150 + and there is no additional line #149, your line will not be displayed. + MAX_ITEM_LINES is defined in IDA.CFG + """ + idaapi.ExtraUpdate(ea, line, idaapi.E_NEXT + n) + + +def DelExtLnA(ea, n): + """ + Delete an additional anterior line + + @param ea: linear address + @param n: number of anterior additioal line (0..500) + + @return: None + """ + idaapi.ExtraDel(ea, idaapi.E_PREV + n) + + +def DelExtLnB(ea, n): + """ + Delete an additional posterior line + + @param ea: linear address + @param n: number of posterior additioal line (0..500) + + @return: None + """ + idaapi.ExtraDel(ea, idaapi.E_NEXT + n) + + +def SetManualInsn(ea, insn): + """ + Specify instruction represenation manually. + + @param ea: linear address + @param insn: a string represenation of the operand + + @note: IDA will not check the specified instruction, it will simply + display it instead of the orginal representation. + """ + return idaapi.set_manual_insn(ea, insn) + + +def GetManualInsn(ea): + """ + Get manual representation of instruction + + @param ea: linear address + + @note: This function returns value set by SetManualInsn earlier. + """ + return idaapi.get_manual_insn(ea) + + +def PatchByte(ea, value): + """ + Change value of a program byte + + @param ea: linear address + @param value: new value of the byte + + @return: None + """ + return idaapi.patch_byte(ea, value) + + +def PatchWord(ea, value): + """ + Change value of a program word (2 bytes) + + @param ea: linear address + @param value: new value of the word + """ + return idaapi.patch_word(ea, value) + + +def PatchDword(ea, value): + """ + Change value of a double word + + @param ea: linear address + @param value: new value of the double word + """ + return idaapi.patch_long(ea, value) + + +def SetFlags(ea, flags): + """ + Set new value of flags + This function should not used be used directly if possible. + It changes properties of a program byte and if misused, may lead to + very-very strange results. + + @param ea: adress + @param flags: new flags value + """ + return idaapi.setFlags(ea, flags) + +_REGMAP = { + 'es' : idaapi.R_es, + 'cs' : idaapi.R_cs, + 'ss' : idaapi.R_ss, + 'ds' : idaapi.R_ds, + 'fs' : idaapi.R_fs, + 'gs' : idaapi.R_gs +} + +def SetReg(ea, reg, value): + """ + Set value of a segment register. + + @param ea: linear address + @param reg: name of a register, like "cs", "ds", "es", etc. + @param value: new value of the segment register. + + @note: IDA keeps tracks of all the points where segment register change their + values. This function allows you to specify the correct value of a segment + register if IDA is not able to find the corrent value. + + """ + if _REGMAP.has_key(reg): + return idaapi.splitSRarea1(ea, _REGMAP[reg], value, 2) + else: + return False + + +def AutoMark2(start, end, queuetype): + """ + Plan to perform an action in the future. + This function will put your request to a special autoanalysis queue. + Later IDA will retrieve the request from the queue and process + it. There are several autoanalysis queue types. IDA will process all + queries from the first queue and then switch to the second queue, etc. + """ + return idaapi.auto_mark_range(start, end, queuetype) + + +def AutoUnmark(start, end, queuetype): + """ + Remove range of addresses from a queue. + """ + return autoUnmark(start, end, queuetype) + + +def AutoMark(ea,qtype): + """ + Plan to analyze an address + """ + return AutoMark2(ea,ea+1,qtype) + +AU_UNK = idaapi.AU_UNK # make unknown +AU_CODE = idaapi.AU_CODE # convert to instruction +AU_PROC = idaapi.AU_PROC # make function +AU_USED = idaapi.AU_USED # reanalyze +AU_LIBF = idaapi.AU_LIBF # apply a flirt signature (the current signature!) +AU_FINAL = idaapi.AU_FINAL # coagulate unexplored items + + +#---------------------------------------------------------------------------- +# P R O D U C E O U T P U T F I L E S +#---------------------------------------------------------------------------- + +def GenerateFile(type, path, ea1, ea2, flags): + """ + Generate an output file + + @param type: type of output file. One of OFILE_... symbols. See below. + @param path: the output file path (will be overwritten!) + @param ea1: start address. For some file types this argument is ignored + @param ea2: end address. For some file types this argument is ignored + @param flags: bit combination of GENFLG_... + + @returns: number of the generated lines. + -1 if an error occured + OFILE_EXE: 0-can't generate exe file, 1-ok + """ + f = idaapi.fopenWT(path) + + if f: + retval = idaapi.gen_file(type, f, ea1, ea2, flags) + idaapi.eclose(f) + return retval + else: + return -1 + + +# output file types: +OFILE_MAP = idaapi.OFILE_MAP +OFILE_EXE = idaapi.OFILE_EXE +OFILE_IDC = idaapi.OFILE_IDC +OFILE_LST = idaapi.OFILE_LST +OFILE_ASM = idaapi.OFILE_ASM +OFILE_DIF = idaapi.OFILE_DIF + +# output control flags: +GENFLG_MAPSEG = idaapi.GENFLG_MAPSEG # map: generate map of segments +GENFLG_MAPNAME = idaapi.GENFLG_MAPNAME # map: include dummy names +GENFLG_MAPDMNG = idaapi.GENFLG_MAPDMNG # map: demangle names +GENFLG_MAPLOC = idaapi.GENFLG_MAPLOC # map: include local names +GENFLG_IDCTYPE = idaapi.GENFLG_IDCTYPE # idc: gen only information about types +GENFLG_ASMTYPE = idaapi.GENFLG_ASMTYPE # asm&lst: gen information about types too +GENFLG_GENHTML = idaapi.GENFLG_GENHTML # asm&lst: generate html (gui version only) +GENFLG_ASMINC = idaapi.GENFLG_ASMINC # asm&lst: gen information only about types + +#---------------------------------------------------------------------------- +# C O M M O N I N F O R M A T I O N +#---------------------------------------------------------------------------- +def GetIdaDirectory (): + """ + Get IDA directory + + This function returns the directory where IDA.EXE resides + """ + return idaapi.idadir() + + +def GetInputFile(): + """ + Get input file name + + This function returns name of the file being disassembled + """ + return idaapi.get_root_filename() + + +def GetInputFilePath(): + """ + Get input file path + + This function returns the full path of the file being disassembled + """ + return idaapi.get_input_file_path() + + +def GetIdbPath(): + """ + Get IDB full path + + This function returns full path of the current IDB database + """ + return idaapi.cvar.database_idb + + +def GetFlags(ea): + """ + Get internal flags + + @param ea: linear address + + @return: 32-bit value of internal flags. See start of IDC.IDC file + for explanations. + """ + return idaapi.getFlags(ea) + + +def Byte(ea): + """ + Get value of program byte + + @param ea: linear address + + @return: value of byte. If byte has no value then returns 0xFF + If the current byte size is different from 8 bits, then the returned value + might have more 1's. + To check if a byte has a value, use functions hasValue(GetFlags(ea)) + """ + return idaapi.get_byte(ea) + + +def GetOriginalByte(ea): + """ + Get original value of program byte + + @param ea: linear address + + @return: the original value of byte before any patch applied to it + """ + return idaapi.get_original_byte(ea) + + +def Word(ea): + """ + Get value of program word (2 bytes) + + @param ea: linear address + + @return: the value of the word. If word has no value then returns 0xFFFF + If the current byte size is different from 8 bits, then the returned value + might have more 1's. + """ + return idaapi.get_word(ea) + + +def Dword(ea): + """ + Get value of program double word (4 bytes) + + @param ea: linear address + + @return: the value of the double word. If double word has no value + then returns 0xFFFFFFFF. + """ + return idaapi.get_long(ea) + + +def GetFloat(ea): + """ + Get value of a floating point number (4 bytes) + + @param ea: linear address + + @return: float + """ + str = chr(idaapi.get_byte(ea)) + \ + chr(idaapi.get_byte(ea+1)) + \ + chr(idaapi.get_byte(ea+2)) + \ + chr(idaapi.get_byte(ea+3)) + + return struct.unpack("f", str)[0] + + +def GetDouble(ea): + """ + Get value of a floating point number (8 bytes) + + @param ea: linear address + + @return: double + """ + str = chr(idaapi.get_byte(ea)) + \ + chr(idaapi.get_byte(ea+1)) + \ + chr(idaapi.get_byte(ea+2)) + \ + chr(idaapi.get_byte(ea+3)) + \ + chr(idaapi.get_byte(ea+4)) + \ + chr(idaapi.get_byte(ea+5)) + \ + chr(idaapi.get_byte(ea+6)) + \ + chr(idaapi.get_byte(ea+7)) + + return struct.unpack("d", str)[0] + + +def LocByName(name): + """ + Get linear address of a name + + @param name: name of program byte + + @return: address of the name + badaddr - no such name + """ + return idaapi.get_name_ea(BADADDR, name) + + +def LocByNameEx(fromaddr, name): + """ + Get linear address of a name + + @param fromaddr: the referring address. Allows to retrieve local label + addresses in functions. If a local name is not found, + then address of a global name is returned. + + @param name: name of program byte + + @return: address of the name (BADADDR - no such name) + """ + return idaapi.get_name_ea(fromaddr, name) + + +def SegByBase(base): + """ + Get segment by segment base + + @param base: segment base paragraph or selector + + @return: linear address of the start of the segment or BADADDR + if no such segment + """ + sel = idaapi.find_selector(base) + seg = idaapi.get_segm_by_sel(sel) + + if seg: + return seg.startEA + else: + return BADADDR + + +def ScreenEA(): + """ + Get linear address of cursor + """ + return idaapi.get_screen_ea() + + +def GetCurrentLine(): + """ + Get the disassembly line at the cursor + + @return: string + """ + return idaapi.tag_remove(idaapi.get_curline()) + + +def SelStart(): + """ + Get start address of the selected area + returns BADADDR - the user has not selected an area + """ + selection, startaddr, endaddr = idaapi.read_selection() + + if selection == 1: + return startaddr + else: + return BADADDR + + +def SelEnd(): + """ + Get end address of the selected area + + @return: BADADDR - the user has not selected an area + """ + selection, startaddr, endaddr = idaapi.read_selection() + + if selection == 1: + return endaddr + else: + return BADADDR + + +def GetReg(ea, reg): + """ + Get value of segment register at the specified address + + @param ea: linear address + @param reg: name of segment register + + @return: the value of the segment register or 0xFFFF on error + + @note: The segment registers in 32bit program usually contain selectors, + so to get paragraph pointed by the segment register you need to + call AskSelector() function. + """ + if _REGMAP.has_key(reg): + return idaapi.getSR(ea, _REGMAP[reg]) & 0xFFFF + else: + return False + + +def NextAddr(ea): + """ + Get next address in the program + + @param ea: linear address + + @return: BADADDR - the specified address in the last used address + """ + return idaapi.nextaddr(ea) + + +def PrevAddr(ea): + """ + Get previous address in the program + + @param ea: linear address + + @return: BADADDR - the specified address in the first address + """ + return idaapi.prevaddr(ea) + + +def NextHead(ea, maxea): + """ + Get next defined item (instruction or data) in the program + + @param ea: linear address to start search from + @param maxea: the search will stop at the address + maxea is not included in the search range + + @return: BADADDR - no (more) defined items + """ + return idaapi.next_head(ea, maxea) + + +def PrevHead(ea, minea): + """ + Get previous defined item (instruction or data) in the program + + @param ea: linear address to start search from + @param minea: the search will stop at the address + minea is included in the search range + + @return: BADADDR - no (more) defined items + """ + return idaapi.prev_head(ea, minea) + + +def NextNotTail(ea): + """ + Get next not-tail address in the program + This function searches for the next displayable address in the program. + The tail bytes of instructions and data are not displayable. + + @param ea: linear address + + @return: BADADDR - no (more) not-tail addresses + """ + return idaapi.next_not_tail(ea) + + +def PrevNotTail(ea): + """ + Get previous not-tail address in the program + This function searches for the previous displayable address in the program. + The tail bytes of instructions and data are not displayable. + + @param ea: linear address + + @return: BADADDR - no (more) not-tail addresses + """ + return idaapi.prev_not_tail(ea) + + +def ItemEnd(ea): + """ + Get address of the end of the item (instruction or data) + + @param ea: linear address + + @return: address past end of the item at 'ea' + """ + return idaapi.get_item_end(ea) + + +def ItemSize(ea): + """ + Get size of instruction or data item in bytes + + @param ea: linear address + + @return: 1..n + """ + return idaapi.get_item_end(ea) - ea + + +def NameEx(fromaddr, ea): + """ + Get visible name of program byte + + This function returns name of byte as it is displayed on the screen. + If a name contains illegal characters, IDA replaces them by the + substitution character during displaying. See IDA.CFG for the + definition of the substitution character. + + @param fromaddr: the referring address. May be BADADDR. + Allows to retrieve local label addresses in functions. + If a local name is not found, then a global name is + returned. + @param ea: linear address + + @return: "" - byte has no name + """ + name = idaapi.get_name(fromaddr, ea) + + if not name: + return "" + else: + return name + + +def GetTrueNameEx(fromaddr, ea): + """ + Get true name of program byte + + This function returns name of byte as is without any replacements. + + @param fromaddr: the referring address. May be BADADDR. + Allows to retrieve local label addresses in functions. + If a local name is not found, then a global name is returned. + @param ea: linear address + + @return: "" - byte has no name + """ + name = idaapi.get_true_name(fromaddr, ea) + + if not name: + return "" + else: + return name + + +def Demangle(name, disable_mask): + """ + Demangle a name + + @param name: name to demangle + @param disable_mask: a mask that tells how to demangle the name + it is a good idea to get this mask using + GetLongPrm(INF_SHORT_DN) or GetLongPrm(INF_LONG_DN) + + @return: a demangled name + If the input name cannot be demangled, returns None + """ + return idaapi.demangle_name(name, disable_mask) + + +def GetDisasm(ea): + """ + Get disassembly line + + @param ea: linear address of instruction + + @return: "" - no instruction at the specified location + + @note: this function may not return exactly the same mnemonics + as you see on the screen. + """ + text = idaapi.generate_disasm_line(ea) + if text: + return idaapi.tag_remove(text) + else: + return "" + + +def GetMnem(ea): + """ + Get instruction mnemonics + + @param ea: linear address of instruction + + @return: "" - no instruction at the specified location + + @note: this function may not return exactly the same mnemonics + as you see on the screen. + """ + res = idaapi.ua_mnem(ea) + + if not res: + return "" + else: + return res + + +def GetOpnd(ea, n): + """ + Get operand of an instruction + + @param ea: linear address of instruction + @param n: number of operand: + 0 - the first operand + 1 - the second operand + + @return: the current text representation of operand + """ + res = idaapi.ua_outop(ea, n) + + if not res: + return "" + else: + return idaapi.tag_remove(res) + + +def GetOpType(ea, n): + """ + Get type of instruction operand + + @param ea: linear address of instruction + @param n: number of operand: + 0 - the first operand + 1 - the second operand + + @return: + - -1 bad operand number passed + - 0 None + - 1 General Register + - 2 Memory Reference + - 3 Base + Index + - 4 Base + Index + Displacement + - 5 Immediate + - 6 Immediate Far Address (with a Segment Selector) + - 7 Immediate Near Address + + B{PC:} + + - 8 386 Trace register + - 9 386 Debug register + - 10 386 Control register + - 11 FPP register + - 12 MMX register + + B{8051:} + + - 8 bit + - 9 /bit + - 10 bit + + B{80196:} + + - 8 [intmem] + - 9 [intmem]+ + - 10 offset[intmem] + - 11 bit + + B{ARM:} + + - 8 shifted register + - 9 MLA operands + - 10 register list (for LDM/STM) + - 11 coprocessor register list (for CDP) + - 12 coprocessor register (for LDC/STC) + + B{PPC:} + + - 8 SPR + - 9 2 FPRs + - 10 SH & MB & ME + - 11 CR field + - 12 CR bit + + B{TMS320C5:} + + - 8 bit + - 9 bit not + - 10 condition + + B{TMS320C6:} + + - 8 register pair (A1:A0..B15:B14) + + B{Z8:} + + - 8 @intmem + - 9 @Rx + + B{Z80:} + + - 8 condition + """ + inslen = idaapi.ua_code(ea) + + if inslen == 0: + return -1 + + insn = idaapi.get_current_instruction() + + if not insn: + return -1 + + op = idaapi.get_instruction_operand(insn, n) + + if not op: + return -1 + + return op.type + + +def GetOperandValue(ea, n): + """ + Get number used in the operand + + This function returns an immediate number used in the operand + + @param ea: linear address of instruction + @param n: the operand number + + @return: value + operand is an immediate value => immediate value + operand has a displacement => displacement + operand is a direct memory ref => memory address + operand is a register => register number + operand is a register phrase => phrase number + otherwise => -1 + """ + inslen = idaapi.ua_code(ea) + + if inslen == 0: + return -1 + + insn = idaapi.get_current_instruction() + + if not insn: + return -1 + + op = idaapi.get_instruction_operand(insn, n) + + if not op: + return -1 + + return op.value + + +def LineA(ea, num): + """ + Get anterior line + + @param ea: linear address + @param num: number of anterior line (0..MAX_ITEM_LINES) + MAX_ITEM_LINES is defined in IDA.CFG + + @return: anterior line string + """ + return idaapi.ExtraGet(ea, E_PREV + num) + + +def LineB(ea, num): + """ + Get posterior line + + @param ea: linear address + @param num: number of posterior line (0..MAX_ITEM_LINES) + + @return: posterior line string + """ + return idaapi.ExtraGet(ea, E_NEXT + num) + + +def GetCommentEx(ea, repeatable): + """ + Get regular indented comment + + @param ea: linear address + + @return: string or None if it fails + """ + return idaapi.get_cmt(ea, repeatable) + + +def AltOp(ea, n): + """ + Get manually entered operand string + + @param ea: linear address + @param n: number of operand: + 0 - the first operand + 1 - the second operand + + @return: string or None if it fails + """ + return idaapi.get_forced_operand(ea, n) + + +def GetStringType(ea): + """ + Get string type + + @param ea: linear address + + Returns one of ASCSTR_... constants + """ + ti = idaapi.typeinfo_t() + + if idaapi.get_typeinfo(ea, 0, GetFlags(ea), ti): + return ti.strtype + else: + return None + +ASCSTR_C = idaapi.ASCSTR_TERMCHR # C-style ASCII string +ASCSTR_PASCAL = idaapi.ASCSTR_PASCAL # Pascal-style ASCII string (length byte) +ASCSTR_LEN2 = idaapi.ASCSTR_LEN2 # Pascal-style, length is 2 bytes +ASCSTR_UNICODE = idaapi.ASCSTR_UNICODE # Unicode string +ASCSTR_LEN4 = idaapi.ASCSTR_LEN4 # Pascal-style, length is 4 bytes +ASCSTR_ULEN2 = idaapi.ASCSTR_ULEN2 # Pascal-style Unicode, length is 2 bytes +ASCSTR_ULEN4 = idaapi.ASCSTR_ULEN4 # Pascal-style Unicode, length is 4 bytes +ASCSTR_LAST = idaapi.ASCSTR_LAST # Last string type + + +# The following functions search for the specified byte +# ea - address to start from +# flag is combination of the following bits + +# returns BADADDR - not found +def FindVoid (ea, flag): return idaapi.find_void(ea, flag) +def FindCode (ea, flag): return idaapi.find_code(ea, flag) +def FindData (ea, flag): return idaapi.find_data(ea, flag) +def FindUnexplored (ea, flag): return idaapi.find_unknown(ea, flag) +def FindExplored (ea, flag): return idaapi.find_defined(ea, flag) +def FindImmediate (ea, flag, value): return idaapi.find_imm(ea, flag, value) + +SEARCH_UP = idaapi.SEARCH_UP # search backward +SEARCH_DOWN = idaapi.SEARCH_DOWN # search forward +SEARCH_NEXT = idaapi.SEARCH_NEXT # search next occurence +SEARCH_CASE = idaapi.SEARCH_CASE # search case-sensitive + # (only for bin&txt search) +SEARCH_REGEX = idaapi.SEARCH_REGEX # enable regular expressions (only for text) +SEARCH_NOBRK = idaapi.SEARCH_NOBRK # don't test ctrl-break +SEARCH_NOSHOW = idaapi.SEARCH_NOSHOW # don't display the search progress + +def FindText(ea, flag, y, x, str): + """ + @param ea: start address + @param flag: combination of SEARCH_* flags + @param y: number of text line at ea to start from (0..MAX_ITEM_LINES) + @param x: coordinate in this line + @param str: search string + + @return: ea of result or BADADDR if not found + """ + return idaapi.find_text(ea, y, x, str, flag) + + +def FindBinary(ea, flag, str, radix=16): + """ + @param ea: start address + @param flag: combination of SEARCH_* flags + @param str: a string as a user enters it for Search Text in Core + @param radix: radix of the numbers (default=16) + + @return: ea of result or BADADDR if not found + + @note: Example: "41 42" - find 2 bytes 41h,42h (radix is 16) + """ + return idaapi.find_binary(ea, BADADDR, str, radix, flag) + + +#---------------------------------------------------------------------------- +# G L O B A L S E T T I N G S M A N I P U L A T I O N +#---------------------------------------------------------------------------- + +# The following functions allow you to set/get common parameters. +# Please note that not all parameters can be set directly. + +def GetLongPrm (offset): + """ + """ + return _IDC_GetAttr(idaapi.cvar.inf, _INFMAP, offset) + + +def GetShortPrm(offset): + return GetLongPrm(offset) + + +def GetCharPrm (offset): + return GetLongPrm(offset) + + +def SetLongPrm (offset, value): + """ + """ + return _IDC_SetAttr(idaapi.cvar.inf, _INFMAP, offset, value) + + +def SetShortPrm(offset, value): + SetLongPrm(offset, value) + + +def SetCharPrm (offset, value): + SetLongPrm(offset, value) + + +INF_VERSION = 3 # short; Version of database +INF_PROCNAME = 5 # char[8]; Name of current processor +INF_LFLAGS = 13 # char; IDP-dependent flags +LFLG_PC_FPP = 0x01 # decode floating point processor + # instructions? +LFLG_PC_FLAT = 0x02 # Flat model? +LFLG_64BIT = 0x04 # 64-bit program? +LFLG_DBG_NOPATH = 0x08 # do not store input full path +LFLG_SNAPSHOT = 0x10 # is memory snapshot? + # in debugger process options +INF_DEMNAMES = 14 # char; display demangled names as: +DEMNAM_CMNT = 0 # comments +DEMNAM_NAME = 1 # regular names +DEMNAM_NONE = 2 # don't display +INF_FILETYPE = 15 # short; type of input file (see ida.hpp) +FT_EXE_OLD = 0 # MS DOS EXE File (obsolete) +FT_COM_OLD = 1 # MS DOS COM File (obsolete) +FT_BIN = 2 # Binary File +FT_DRV = 3 # MS DOS Driver +FT_WIN = 4 # New Executable (NE) +FT_HEX = 5 # Intel Hex Object File +FT_MEX = 6 # MOS Technology Hex Object File +FT_LX = 7 # Linear Executable (LX) +FT_LE = 8 # Linear Executable (LE) +FT_NLM = 9 # Netware Loadable Module (NLM) +FT_COFF = 10 # Common Object File Format (COFF) +FT_PE = 11 # Portable Executable (PE) +FT_OMF = 12 # Object Module Format +FT_SREC = 13 # R-records +FT_ZIP = 14 # ZIP file (this file is never loaded to IDA database) +FT_OMFLIB = 15 # Library of OMF Modules +FT_AR = 16 # ar library +FT_LOADER = 17 # file is loaded using LOADER DLL +FT_ELF = 18 # Executable and Linkable Format (ELF) +FT_W32RUN = 19 # Watcom DOS32 Extender (W32RUN) +FT_AOUT = 20 # Linux a.out (AOUT) +FT_PRC = 21 # PalmPilot program file +FT_EXE = 22 # MS DOS EXE File +FT_COM = 23 # MS DOS COM File +FT_AIXAR = 24 # AIX ar library +INF_FCORESIZ = 17 +INF_CORESTART = 21 +INF_OSTYPE = 25 # short; FLIRT: OS type the program is for +OSTYPE_MSDOS = 0x0001 +OSTYPE_WIN = 0x0002 +OSTYPE_OS2 = 0x0004 +OSTYPE_NETW = 0x0008 +INF_APPTYPE = 27 # short; FLIRT: Application type +APPT_CONSOLE = 0x0001 # console +APPT_GRAPHIC = 0x0002 # graphics +APPT_PROGRAM = 0x0004 # EXE +APPT_LIBRARY = 0x0008 # DLL +APPT_DRIVER = 0x0010 # DRIVER +APPT_1THREAD = 0x0020 # Singlethread +APPT_MTHREAD = 0x0040 # Multithread +APPT_16BIT = 0x0080 # 16 bit application +APPT_32BIT = 0x0100 # 32 bit application +INF_START_SP = 29 # long; SP register value at the start of + # program execution +INF_START_AF = 33 # short; Analysis flags: +AF_FIXUP = 0x0001 # Create offsets and segments using fixup info +AF_MARKCODE = 0x0002 # Mark typical code sequences as code +AF_UNK = 0x0004 # Delete instructions with no xrefs +AF_CODE = 0x0008 # Trace execution flow +AF_PROC = 0x0010 # Create functions if call is present +AF_USED = 0x0020 # Analyze and create all xrefs +AF_FLIRT = 0x0040 # Use flirt signatures +AF_PROCPTR = 0x0080 # Create function if data xref data->code32 exists +AF_JFUNC = 0x0100 # Rename jump functions as j_... +AF_NULLSUB = 0x0200 # Rename empty functions as nullsub_... +AF_LVAR = 0x0400 # Create stack variables +AF_TRACE = 0x0800 # Trace stack pointer +AF_ASCII = 0x1000 # Create ascii string if data xref exists +AF_IMMOFF = 0x2000 # Convert 32bit instruction operand to offset +AF_DREFOFF = 0x4000 # Create offset if data xref to seg32 exists +AF_FINAL = 0x8000 # Final pass of analysis +INF_START_IP = 35 # long; IP register value at the start of + # program execution +INF_BEGIN_EA = 39 # long; Linear address of program entry point +INF_MIN_EA = 43 # long; The lowest address used + # in the program +INF_MAX_EA = 47 # long; The highest address used + # in the program - = 1 +INF_OMIN_EA = 51 +INF_OMAX_EA = 55 +INF_LOW_OFF = 59 # long; low limit of voids +INF_HIGH_OFF = 63 # long; high limit of voids +INF_MAXREF = 67 # long; max xref depth +INF_ASCII_BREAK = 71 # char; ASCII line break symbol +INF_WIDE_HIGH_BYTE_FIRST = 72 +INF_INDENT = 73 # char; Indention for instructions +INF_COMMENT = 74 # char; Indention for comments +INF_XREFNUM = 75 # char; Number of references to generate + # = 0 - xrefs wont be generated at all +INF_ENTAB = 76 # char; Use '\t' chars in the output file? +INF_SPECSEGS = 77 +INF_VOIDS = 78 # char; Display void marks? +INF_SHOWAUTO = 80 # char; Display autoanalysis indicator? +INF_AUTO = 81 # char; Autoanalysis is enabled? +INF_BORDER = 82 # char; Generate borders? +INF_NULL = 83 # char; Generate empty lines? +INF_GENFLAGS = 84 # char; General flags: +INFFL_LZERO = 0x01 # generate leading zeroes in numbers +INF_SHOWPREF = 85 # char; Show line prefixes? +INF_PREFSEG = 86 # char; line prefixes with segment name? +INF_ASMTYPE = 87 # char; target assembler number (0..n) +INF_BASEADDR = 88 # long; base paragraph of the program +INF_XREFS = 92 # char; xrefs representation: +SW_SEGXRF = 0x01 # show segments in xrefs? +SW_XRFMRK = 0x02 # show xref type marks? +SW_XRFFNC = 0x04 # show function offsets? +SW_XRFVAL = 0x08 # show xref values? (otherwise-"...") +INF_BINPREF = 93 # short; # of instruction bytes to show + # in line prefix +INF_CMTFLAG = 95 # char; comments: +SW_RPTCMT = 0x01 # show repeatable comments? +SW_ALLCMT = 0x02 # comment all lines? +SW_NOCMT = 0x04 # no comments at all +SW_LINNUM = 0x08 # show source line numbers +SW_MICRO = 0x10 # show microcode (if implemented) +INF_NAMETYPE = 96 # char; dummy names represenation type +NM_REL_OFF = 0 +NM_PTR_OFF = 1 +NM_NAM_OFF = 2 +NM_REL_EA = 3 +NM_PTR_EA = 4 +NM_NAM_EA = 5 +NM_EA = 6 +NM_EA4 = 7 +NM_EA8 = 8 +NM_SHORT = 9 +NM_SERIAL = 10 +INF_SHOWBADS = 97 # char; show bad instructions? + # an instruction is bad if it appears + # in the ash.badworks array + +INF_PREFFLAG = 98 # char; line prefix type: +PREF_SEGADR = 0x01 # show segment addresses? +PREF_FNCOFF = 0x02 # show function offsets? +PREF_STACK = 0x04 # show stack pointer? + +INF_PACKBASE = 99 # char; pack database? + +INF_ASCIIFLAGS = 100 # uchar; ascii flags +ASCF_GEN = 0x01 # generate ASCII names? +ASCF_AUTO = 0x02 # ASCII names have 'autogenerated' bit? +ASCF_SERIAL = 0x04 # generate serial names? +ASCF_COMMENT = 0x10 # generate auto comment for ascii references? +ASCF_SAVECASE = 0x20 # preserve case of ascii strings for identifiers + +INF_LISTNAMES = 101 # uchar; What names should be included in the list? +LN_NORMAL = 0x01 # normal names +LN_PUBLIC = 0x02 # public names +LN_AUTO = 0x04 # autogenerated names +LN_WEAK = 0x08 # weak names + +INF_ASCIIPREF = 102 # char[16];ASCII names prefix +INF_ASCIISERNUM = 118 # ulong; serial number +INF_ASCIIZEROES = 122 # char; leading zeroes +INF_MF = 126 # uchar; Byte order: 1==MSB first +INF_ORG = 127 # char; Generate 'org' directives? +INF_ASSUME = 128 # char; Generate 'assume' directives? +INF_CHECKARG = 129 # char; Check manual operands? +INF_START_SS = 130 # long; value of SS at the start +INF_START_CS = 134 # long; value of CS at the start +INF_MAIN = 138 # long; address of main() +INF_SHORT_DN = 142 # long; short form of demangled names +INF_LONG_DN = 146 # long; long form of demangled names + # see demangle.h for definitions +INF_DATATYPES = 150 # long; data types allowed in data carousel +INF_STRTYPE = 154 # long; current ascii string type + # is considered as several bytes: + # low byte: +ASCSTR_TERMCHR = 0 # Character-terminated ASCII string +ASCSTR_C = 0 # C-string, zero terminated +ASCSTR_PASCAL = 1 # Pascal-style ASCII string (length byte) +ASCSTR_LEN2 = 2 # Pascal-style, length is 2 bytes +ASCSTR_UNICODE = 3 # Unicode string +ASCSTR_LEN4 = 4 # Delphi string, length is 4 bytes +ASCSTR_ULEN2 = 5 # Pascal-style Unicode, length is 2 bytes +ASCSTR_ULEN4 = 6 # Pascal-style Unicode, length is 4 bytes + +# = 2nd byte - termination chracters for ASCSTR_TERMCHR: +#STRTERM1(strtype) ((strtype>>8)&0xFF) +# = 3d byte: +#STRTERM2(strtype) ((strtype>>16)&0xFF) + # The termination characters are kept in + # the = 2nd and 3d bytes of string type + # if the second termination character is + # '\0', then it is ignored. +INF_AF2 = 158 # ushort; Analysis flags 2 +AF2_JUMPTBL = 0x0001 # Locate and create jump tables +AF2_DODATA = 0x0002 # Coagulate data segs in final pass +AF2_HFLIRT = 0x0004 # Automatically hide library functions +AF2_STKARG = 0x0008 # Propagate stack argument information +AF2_REGARG = 0x0010 # Propagate register argument information +AF2_CHKUNI = 0x0020 # Check for unicode strings +AF2_SIGCMT = 0x0040 # Append a signature name comment for recognized anonymous library functions +AF2_SIGMLT = 0x0080 # Allow recognition of several copies of the same function +AF2_FTAIL = 0x0100 # Create function tails +AF2_DATOFF = 0x0200 # Automatically convert data to offsets +AF2_ANORET = 0x0400 # Perform 'no-return' analysis +AF2_VERSP = 0x0800 # Perform full stack pointer analysis +AF2_DOCODE = 0x1000 # Coagulate code segs at the final pass + +INF_NAMELEN = 160 # ushort; max name length (without zero byte) +INF_MARGIN = 162 # ushort; max length of data lines +INF_LENXREF = 164 # ushort; max length of line with xrefs +INF_LPREFIX = 166 # char[16];prefix of local names + # if a new name has this prefix, + # it will be automatically converted to a local name +INF_LPREFIXLEN = 182 # uchar; length of the lprefix +INF_COMPILER = 183 # uchar; compiler +COMP_MASK = 0x0F +COMP_UNK = 0x00 # Unknown +COMP_MS = 0x01 # Visual C++ +COMP_BC = 0x02 # Borland C++ +COMP_WATCOM = 0x03 # Watcom C++ +COMP_GNU = 0x06 # GNU C++ +COMP_VISAGE = 0x07 # Visual Age C++ +COMP_BP = 0x08 # Delphi + +INF_MODEL = 184 # uchar; memory model & calling convention +INF_SIZEOF_INT = 185 # uchar; sizeof(int) +INF_SIZEOF_BOOL = 186 # uchar; sizeof(bool) +INF_SIZEOF_ENUM = 187 # uchar; sizeof(enum) +INF_SIZEOF_ALGN = 188 # uchar; default alignment +INF_SIZEOF_SHORT = 189 +INF_SIZEOF_LONG = 190 +INF_SIZEOF_LLONG = 191 + +_INFMAP = { +INF_VERSION : 'version', # short; Version of database +INF_PROCNAME : 'procname', # char[8]; Name of current processor +INF_LFLAGS : 'lflags', # char; IDP-dependent flags +INF_DEMNAMES : 'demnames', # char; display demangled names as: +INF_FILETYPE : 'filetype', # short; type of input file (see ida.hpp) +INF_FCORESIZ : 'fcoresize', +INF_CORESTART : 'corestart', +INF_OSTYPE : 'ostype', # short; FLIRT: OS type the program is for +INF_APPTYPE : 'apptype', # short; FLIRT: Application type +INF_START_SP : 'startSP', # long; SP register value at the start of +INF_START_AF : 'af', # short; Analysis flags: +INF_START_IP : 'startIP', # long; IP register value at the start of +INF_BEGIN_EA : 'beginEA', # long; Linear address of program entry point +INF_MIN_EA : 'minEA', # long; The lowest address used +INF_MAX_EA : 'maxEA', # long; The highest address used +INF_OMIN_EA : 'ominEA', +INF_OMAX_EA : 'omaxEA', +INF_LOW_OFF : 'lowoff', # long; low limit of voids +INF_HIGH_OFF : 'highoff', # long; high limit of voids +INF_MAXREF : 'maxref', # long; max xref depth +INF_ASCII_BREAK : 'ASCIIbreak', # char; ASCII line break symbol +INF_WIDE_HIGH_BYTE_FIRST : 'wide_high_byte_first', +INF_INDENT : 'indent', # char; Indention for instructions +INF_COMMENT : 'comment', # char; Indention for comments +INF_XREFNUM : 'xrefnum', # char; Number of references to generate +INF_ENTAB : 's_entab', # char; Use '\t' chars in the output file? +INF_SPECSEGS : 'specsegs', +INF_VOIDS : 's_void', # char; Display void marks? +INF_SHOWAUTO : 's_showauto', # char; Display autoanalysis indicator? +INF_AUTO : 's_auto', # char; Autoanalysis is enabled? +# FIXME: This might be incorrect +INF_BORDER : 's_limiter', # char; Generate borders? +INF_NULL : 's_null', # char; Generate empty lines? +INF_GENFLAGS : 's_genflags', # char; General flags: +INF_SHOWPREF : 's_showpref', # char; Show line prefixes? +INF_PREFSEG : 's_prefseg', # char; line prefixes with segment name? +INF_ASMTYPE : 'asmtype', # char; target assembler number (0..n) +INF_BASEADDR : 'baseaddr', # long; base paragraph of the program +INF_XREFS : 's_xrefflag', # char; xrefs representation: +INF_BINPREF : 'binSize', # short; # of instruction bytes to show +INF_CMTFLAG : 's_cmtflg', # char; comments: +INF_NAMETYPE : 'nametype', # char; dummy names represenation type +INF_SHOWBADS : 's_showbads', # char; show bad instructions? +INF_PREFFLAG : 's_prefflag', # char; line prefix type: +INF_PACKBASE : 's_packbase', # char; pack database? +INF_ASCIIFLAGS : 'asciiflags', # uchar; ascii flags +INF_LISTNAMES : 'listnames', # uchar; What names should be included in the list? +INF_ASCIIPREF : 'ASCIIpref', # char[16];ASCII names prefix +INF_ASCIISERNUM : 'ASCIIsernum', # ulong; serial number +INF_ASCIIZEROES : 'ASCIIzeroes', # char; leading zeroes +INF_MF : 'mf', # uchar; Byte order: 1==MSB first +INF_ORG : 's_org', # char; Generate 'org' directives? +INF_ASSUME : 's_assume', # char; Generate 'assume' directives? +INF_CHECKARG : 's_checkarg', # char; Check manual operands? +INF_START_SS : 'start_ss', # long; value of SS at the start +INF_START_CS : 'start_cs', # long; value of CS at the start +INF_MAIN : 'main', # long; address of main() +INF_SHORT_DN : 'short_demnames', # long; short form of demangled names +INF_LONG_DN : 'long_demnames', # long; long form of demangled names +INF_DATATYPES : 'datatypes', # long; data types allowed in data carousel +INF_STRTYPE : 'strtype', # long; current ascii string type +INF_AF2 : 'af2', # ushort; Analysis flags 2 +INF_NAMELEN : 'namelen', # ushort; max name length (without zero byte) +INF_MARGIN : 'margin', # ushort; max length of data lines +INF_LENXREF : 'lenxref', # ushort; max length of line with xrefs +INF_LPREFIX : 'lprefix', # char[16];prefix of local names +INF_LPREFIXLEN : 'lprefixlen', # uchar; length of the lprefix +INF_COMPILER : 'cc' # uchar; compiler + +#INF_MODEL = 184 # uchar; memory model & calling convention +#INF_SIZEOF_INT = 185 # uchar; sizeof(int) +#INF_SIZEOF_BOOL = 186 # uchar; sizeof(bool) +#INF_SIZEOF_ENUM = 187 # uchar; sizeof(enum) +#INF_SIZEOF_ALGN = 188 # uchar; default alignment +#INF_SIZEOF_SHORT = 189 +#INF_SIZEOF_LONG = 190 +#INF_SIZEOF_LLONG = 191 +} + + +def SetProcessorType (processor, level): + """ + Change current processor + + @param processor: name of processor in short form. + run 'ida ?' to get list of allowed processor types + @param level: the power of request: + SETPROC_COMPAT - search for the processor type in the current module + SETPROC_ALL - search for the processor type in all modules + only if there were not calls with SETPROC_USER + SETPROC_USER - search for the processor type in all modules + and prohibit level SETPROC_USER + SETPROC_FATAL - can be combined with previous bits. + means that if the processor type can't be + set, IDA should display an error message and exit. + """ + return idaapi.set_processor_type(processor, level) + +SETPROC_COMPAT = idaapi.SETPROC_COMPAT +SETPROC_ALL = idaapi.SETPROC_ALL +SETPROC_USER = idaapi.SETPROC_USER +SETPROC_FATAL = idaapi.SETPROC_FATAL + +def SetPrcsr(processor): return SetProcessorType(processor, SETPROC_COMPAT) + + +def Batch(batch): + """ + Enable/disable batch mode of operation + + @param batch: Batch mode + 0 - ida will display dialog boxes and wait for the user input + 1 - ida will not display dialog boxes, warnings, etc. + + @return: old balue of batch flag + """ + batch_prev = idaapi.cvar.batch + idaapi.cvar.batch = batch + return batch_prev + + +#---------------------------------------------------------------------------- +# I N T E R A C T I O N W I T H T H E U S E R +#---------------------------------------------------------------------------- +def AskStr(defval, prompt): + """ + Ask the user to enter a string + + @param defval: the default string value. This value will appear + in the dialog box. + @param prompt: the prompt to display in the dialog box + + @return: the entered string or 0. + """ + return idaapi.askstr(idaapi.HIST_IDENT, defval, prompt) + + +def AskFile(forsave, mask, prompt): + """ + Ask the user to choose a file + + @param forsave: 0: "Open" dialog box, 1: "Save" dialog box + @param mask: the input file mask as "*.*" or the default file name. + @param prompt: the prompt to display in the dialog box + + @return: the selected file or 0. + """ + return idaapi.askfile_c(forsave, mask, prompt) + + +def AskAddr(defval, prompt): + """ + Ask the user to enter an address + + @param defval: the default address value. This value + will appear in the dialog box. + @param prompt: the prompt to display in the dialog box + + @return: the entered address or BADADDR. + """ + return idaapi.askaddr(defval, prompt) + + +def AskLong(defval, prompt): + """ + Ask the user to enter a number + + @param defval: the default value. This value + will appear in the dialog box. + @param prompt: the prompt to display in the dialog box + + @return: the entered number or -1. + """ + return idaapi.asklong(defval, prompt) + + +def AskSeg(defval, prompt): + """ + Ask the user to enter a segment value + + @param defval: the default value. This value + will appear in the dialog box. + @param prompt: the prompt to display in the dialog box + + @return: the entered segment selector or BADSEL. + """ + return idaapi.askseg(defval, prompt) + + +def AskIdent(defval, prompt): + """ + Ask the user to enter an identifier + + @param defval: the default identifier. This value will appear in + the dialog box. + @param prompt: the prompt to display in the dialog box + + @return: the entered identifier or 0. + """ + return idaapi.askident(defval, prompt) + + +def AskYN(defval, prompt): + """ + Ask the user a question and let him answer Yes/No/Cancel + + @param defval: the default answer. This answer will be selected if the user + presses Enter. -1:cancel,0-no,1-ok + @param prompt: the prompt to display in the dialog box + + @return: -1:cancel,0-no,1-ok + """ + return idaapi.askyn_c(defval, prompt) + + +def Message(msg): + """ + Display a message in the message window + + @param msg: message to print (formatting is done in Python) + + This function can be used to debug IDC scripts + """ + idaapi.msg(msg) + + +def Warning(msg): + """ + Display a message in a message box + + @param msg: message to print (formatting is done in Python) + + This function can be used to debug IDC scripts + The user will be able to hide messages if they appear twice in a row on + the screen + """ + idaapi.warning(msg) + + +def Fatal(format): + """ + Display a fatal message in a message box and quit IDA + + @param format: message to print + """ + idaapi.error(format) + + +def SetStatus(status): + """ + Change IDA indicator. + + @param status: new status + + @return: the previous status. + """ + return idaapi.setStat(status) + + +IDA_STATUS_READY = 0 # READY IDA is idle +IDA_STATUS_THINKING = 1 # THINKING Analyzing but the user may press keys +IDA_STATUS_WAITING = 2 # WAITING Waiting for the user input +IDA_STATUS_WORK = 3 # BUSY IDA is busy + +def Refresh(): + """ + Refresh all disassembly views + """ + idaapi.refresh_idaview_anyway() + + +def RefreshLists(): + """ + Refresh all list views (names, functions, etc) + + FIXME: unimplemented + """ + raise NotImplementedError + + +#---------------------------------------------------------------------------- +# S E G M E N T A T I O N +#---------------------------------------------------------------------------- +def AskSelector(sel): + """ + Get a selector value + + @param sel: the selector number + + @return: selector value if found + otherwise the input value (sel) + + @note: selector values are always in paragraphs + """ + sel = idaapi.getn_selector(sel) + + if not sel: + return sel + else: + return sel.base + + +def FindSelector(val): + """ + Find a selector which has the specifed value + + @param val: value to search for + + @return: the selector number if found, + otherwise the input value (val & 0xFFFF) + + @note: selector values are always in paragraphs + """ + sel = idaapi.find_selector(val) + + if not sel: + return val & 0xffff + else: + return sel.n + + +def SetSelector(sel, value): + """ + Set a selector value + + @param sel: the selector number + @param value: value of selector + + @return: None + + @note: ida supports up to 4096 selectors. + if 'sel' == 'val' then the selector is destroyed because + it has no significance + """ + return idaapi.set_selector(sel, value) + + +def DelSelector(sel): + """ + Delete a selector + + @param sel: the selector number to delete + + @return: None + + @note: if the selector is found, it will be deleted + """ + return idaapi.del_selector(sel) + + +def FirstSeg(): + """ + Get first segment + + @return: address of the start of the first segment + BADADDR - no segments are defined + """ + segn = idaapi.get_segm_qty() + + if segn == 0: + return BADADDR + else: + seg = idaapi.getnseg(0) + + if not seg: + return BADADDR + else: + return seg.startEA + + +def NextSeg(ea): + """ + Get next segment + + @param ea: linear address + + @return: start of the next segment + BADADDR - no next segment + + TODO: Any better way of doing this? + """ + + for n in range(idaapi.get_segm_qty()): + currseg = idaapi.getnseg(n) + + if ea >= currseg.startEA and ea < currseg.endEA: + nextseg = idaapi.getnseg(n+1) + + if not nextseg: + return BADADDR + else: + return nextseg.startEA + + return BADADDR + + +def SegStart(ea): + """ + Get start address of a segment + + @param ea: any address in the segment + + @return: start of segment + BADADDR - the specified address doesn't belong to any segment + """ + seg = idaapi.getseg(ea) + + if not seg: + return BADADDR + else: + return seg.startEA + + +def SegEnd(ea): + """ + Get end address of a segment + + @param ea: any address in the segment + + @return: end of segment (an address past end of the segment) + BADADDR - the specified address doesn't belong to any segment + """ + seg = idaapi.getseg(ea) + + if not seg: + return BADADDR + else: + return seg.endEA + + +def SegName(ea): + """ + Get name of a segment + + @param ea: any address in the segment + + @return: "" - no segment at the specified address + """ + seg = idaapi.getseg(ea) + + if not seg: + return "" + else: + name = idaapi.get_true_segm_name(seg) + + if not name: + return "" + else: + return name + + +def SegCreate(startea, endea, base, use32, align, comb): + """ + Create a new segment + + @param startea: linear address of the start of the segment + @param endea: linear address of the end of the segment + this address will not belong to the segment + 'endea' should be higher than 'startea' + @param base: base paragraph or selector of the segment. + a paragraph is 16byte memory chunk. + If a selector value is specified, the selector should be + already defined. + @param use32: 0: 16bit segment, 1: 32bit segment, 2: 64bit segment + @param align: segment alignment. see below for alignment values + @param comb: segment combination. see below for combination values. + + @return: 0-failed, 1-ok + """ + success = idaapi.add_segm(base, startea, endea, "Segment", "CODE") + + if success != 1: + return 0 + + seg = idaapi.getseg(startea) + + if not seg: + return 0 + + seg.bitness = use32 + seg.align = align + seg.comb = comb + + return 1 + + +def SegDelete(ea, flags): + """ + Delete a segment + + @param ea: any address in the segment + @param flags: combination of SEGDEL_* flags + + @return: boolean success + """ + return idaapi.del_segm(ea, disable) + +SEGDEL_PERM = idaapi.SEGDEL_PERM # permanently, i.e. disable addresses +SEGDEL_KEEP = idaapi.SEGDEL_KEEP # keep information (code & data, etc) +SEGDEL_SILENT = idaapi.SEGDEL_SILENT # be silent + +def SegBounds(ea, startea, endea, disable): + """ + Change segment boundaries + + @param ea: any address in the segment + @param startea: new start address of the segment + @param endea: new end address of the segment + @param disable: discard bytes that go out of the segment + + @return: boolean success + """ + return idaapi.set_segm_start(ea, startea, disable) & \ + idaapi.set_segm_end(ea, endea, disable) + + +def SegRename(ea, name): + """ + Change name of the segment + + @param ea: any address in the segment + @param name: new name of the segment + + @return: success (boolean) + """ + seg = idaapi.getseg(ea) + + if not seg: + return False + + return idaapi.set_segm_name(seg, name) + + +def SegClass(ea, segclass): + """ + Change class of the segment + + @param ea: any address in the segment + @param segclass: new class of the segment + + @return: success (boolean) + """ + seg = idaapi.getseg(ea) + + if not seg: + return False + + return idaapi.set_segm_class(seg, segclass) + + +def SegAlign(ea, alignment): + """ + Change alignment of the segment + + @param ea: any address in the segment + @param alignment: new alignment of the segment (one of the sa... constants) + + @return: success (boolean) + """ + return SetSegmentAttr(ea, SEGATTR_ALIGN, alignment) + + +saAbs = idaapi.saAbs # Absolute segment. +saRelByte = idaapi.saRelByte # Relocatable, byte aligned. +saRelWord = idaapi.saRelWord # Relocatable, word (2-byte, 16-bit) aligned. +saRelPara = idaapi.saRelPara # Relocatable, paragraph (16-byte) aligned. +saRelPage = idaapi.saRelPage # Relocatable, aligned on 256-byte boundary + # (a "page" in the original Intel specification). +saRelDble = idaapi.saRelDble # Relocatable, aligned on a double word + # (4-byte) boundary. This value is used by + # the PharLap OMF for the same alignment. +saRel4K = idaapi.saRel4K # This value is used by the PharLap OMF for + # page (4K) alignment. It is not supported + # by LINK. +saGroup = idaapi.saGroup # Segment group +saRel32Bytes = idaapi.saRel32Bytes # 32 bytes +saRel64Bytes = idaapi.saRel64Bytes # 64 bytes +saRelQword = idaapi.saRelQword # 8 bytes + + +def SegComb(segea, comb): + """ + Change combination of the segment + + @param segea: any address in the segment + @param comb: new combination of the segment (one of the sc... constants) + + @return: success (boolean) + """ + return SetSegmentAttr(ea, SEGATTR_COMB, comb) + + +scPriv = idaapi.scPriv # Private. Do not combine with any other program + # segment. +scPub = idaapi.scPub # Public. Combine by appending at an offset that + # meets the alignment requirement. +scPub2 = idaapi.scPub2 # As defined by Microsoft, same as C=2 (public). +scStack = idaapi.scStack # Stack. Combine as for C=2. This combine type + # forces byte alignment. +scCommon = idaapi.scCommon # Common. Combine by overlay using maximum size. +scPub3 = idaapi.scPub3 # As defined by Microsoft, same as C=2 (public). + + +def SegAddrng(ea, bitness): + """ + Change segment addressing + + @param ea: any address in the segment + @param bitness: 0: 16bit, 1: 32bit, 2: 64bit + + @return: success (boolean) + """ + seg = idaapi.getseg(segea) + + if not seg: + return False + + seg.bitness = use32 + + return True + + +def SegByName(segname): + """ + Get segment by name + + @param segname: name of segment + + @return: segment selector or BADADDR + """ + seg = idaapi.get_segm_by_name(segname) + + if not seg: + return BADADDR + + return seg.startEA + + +def SegDefReg(ea, reg, value): + """ + Set default segment register value for a segment + + @param ea: any address in the segment + if no segment is present at the specified address + then all segments will be affected + @param reg: name of segment register + @param value: default value of the segment register. -1-undefined. + """ + seg = idaapi.getseg(ea) + + if seg and _REGMAP.has_key(reg): + return idaapi.SetDefaultRegisterValue(seg, _REGMAP[reg], value) + else: + return False + + +def SetSegmentType(segea, type): + """ + Set segment type + + @param segea: any address within segment + @param type: new segment type: + + @return: !=0 - ok + """ + seg = idaapi.getseg(segea) + + if not seg: + return False + + seg.type = type + return seg.update() + + +SEG_NORM = idaapi.SEG_NORM +SEG_XTRN = idaapi.SEG_XTRN # * segment with 'extern' definitions + # no instructions are allowed +SEG_CODE = idaapi.SEG_CODE # pure code segment +SEG_DATA = idaapi.SEG_DATA # pure data segment +SEG_IMP = idaapi.SEG_IMP # implementation segment +SEG_GRP = idaapi.SEG_GRP # * group of segments + # no instructions are allowed +SEG_NULL = idaapi.SEG_NULL # zero-length segment +SEG_UNDF = idaapi.SEG_UNDF # undefined segment type +SEG_BSS = idaapi.SEG_BSS # uninitialized segment +SEG_ABSSYM = idaapi.SEG_ABSSYM # * segment with definitions of absolute symbols + # no instructions are allowed +SEG_COMM = idaapi.SEG_COMM # * segment with communal definitions + # no instructions are allowed +SEG_IMEM = idaapi.SEG_IMEM # internal processor memory & sfr (8051) + + +def GetSegmentAttr(segea, attr): + """ + Get segment attribute + + @param segea: any address within segment + @param attr: one of SEGATTR_... constants + + FIXME: add support for segment registers + """ + seg = idaapi.getseg(segea) + + if seg: + return _IDC_GetAttr(seg, _SEGATTRMAP, attr) + + +def SetSegmentAttr(segea, attr, value): + """ + Set segment attribute + + @param segea: any address within segment + @param attr: one of SEGATTR_... constants + + @note: Please note that not all segment attributes are modifiable. + Also some of them should be modified using special functions + like SegAddrng, etc. + + FIXME: add support for segment registers + """ + seg = idaapi.getseg(segea) + + if seg: + _IDC_SetAttr(seg, _SEGATTRMAP, attr, value) + return seg.update() + + +SEGATTR_START = 0 # starting address +SEGATTR_END = 4 # ending address +SEGATTR_ORGBASE = 16 +SEGATTR_ALIGN = 20 # alignment +SEGATTR_COMB = 21 # combination +SEGATTR_PERM = 22 # permissions +SEGATTR_BITNESS = 23 # bitness (0: 16, 1: 32, 2: 64 bit segment) + # Note: modifying the attribute directly does + # not lead to the reanalysis of the segment. + # Using SegAddrng() is more correct. +SEGATTR_FLAGS = 24 # segment flags +SEGATTR_SEL = 26 # segment selector +SEGATTR_ES = 30 # default ES value +SEGATTR_CS = 34 # default CS value +SEGATTR_SS = 38 # default SS value +SEGATTR_DS = 42 # default DS value +SEGATTR_FS = 46 # default FS value +SEGATTR_GS = 50 # default GS value +SEGATTR_TYPE = 94 # segment type +SEGATTR_COLOR = 95 # segment color + +_SEGATTRMAP = { + SEGATTR_START : 'startEA', + SEGATTR_END : 'endEA', + SEGATTR_ORGBASE : 'orgbase', + SEGATTR_ALIGN : 'align', + SEGATTR_COMB : 'comb', + SEGATTR_PERM : 'perm', + SEGATTR_BITNESS : 'bitness', + SEGATTR_FLAGS : 'flags', + SEGATTR_SEL : 'sel', + SEGATTR_ES : '', + SEGATTR_CS : '', + SEGATTR_SS : '', + SEGATTR_DS : '', + SEGATTR_FS : '', + SEGATTR_GS : '', + SEGATTR_TYPE : 'type', + SEGATTR_COLOR : 'color', +} + + +#---------------------------------------------------------------------------- +# C R O S S R E F E R E N C E S +#---------------------------------------------------------------------------- +# Flow types (combine with XREF_USER!): +fl_CF = 16 # Call Far +fl_CN = 17 # Call Near +fl_JF = 18 # Jump Far +fl_JN = 19 # Jump Near +fl_F = 21 # Ordinary flow + +XREF_USER = 32 # All user-specified xref types + # must be combined with this bit + + +# Mark exec flow 'from' 'to' +def AddCodeXref(From, To, flowtype): + """ + """ + return idaapi.add_cref(From, To, flowtype) + + +def DelCodeXref(From, To, undef): + """ + Unmark exec flow 'from' 'to' + + @param undef: make 'To' undefined if no more references to it + + @returns: 1 - planned to be made undefined + """ + return idaapi.del_cref(From, To, undef) + + +# The following functions include the ordinary flows: +# (the ordinary flow references are returned first) +def Rfirst(From): + """ + Get first code xref from 'From' + """ + return idaapi.get_first_cref_from(From) + + +def Rnext(From, current): + """ + Get next code xref from + """ + return idaapi.get_next_cref_from(From, current) + + +def RfirstB(To): + """ + Get first code xref to 'To' + """ + return idaapi.get_first_cref_to(To) + + +def RnextB(To, current): + """ + Get next code xref to 'To' + """ + return idaapi.get_next_cref_to(To, current) + + +# The following functions don't take into account the ordinary flows: +def Rfirst0(From): + """ + Get first xref from 'From' + """ + return idaapi.get_first_fcref_from(From) + + +def Rnext0(From, current): + """ + Get next xref from + """ + return idaapi.get_next_fcref_from(From, current) + + +def RfirstB0(To): + """ + Get first xref to 'To' + """ + return idaapi.get_first_fcref_to(To) + + +def RnextB0(To, current): + """ + Get next xref to 'To' + """ + return idaapi.get_next_fcref_to(To, current) + + +# Data reference types (combine with XREF_USER!): +dr_O = idaapi.dr_O # Offset +dr_W = idaapi.dr_W # Write +dr_R = idaapi.dr_R # Read +dr_T = idaapi.dr_T # Text (names in manual operands) +dr_I = idaapi.dr_I # Informational + + +def add_dref(From, To, drefType): + """ + Create Data Ref + """ + return idaapi.add_dref(From, To, drefType) + + +def del_dref(From, To): + """ + Unmark Data Ref + """ + return idaapi.del_dref(From, To) + + +def Dfirst(From): + """ + Get first data xref from 'From' + """ + return idaapi.get_first_dref_from(From) + + +def Dnext(From, current): + """ + Get next data xref from 'From' + """ + return idaapi.get_next_dref_from(From, current) + + +def DfirstB(To): + """ + Get first data xref to 'To' + """ + return idaapi.get_first_dref_to(To) + + +def DnextB(To, current): + """ + Get next data xref to 'To' + """ + return idaapi.get_next_dref_to(To, current) + + +def XrefType(): + """ + Return type of the last xref obtained by + [RD]first/next[B0] functions. + + @return: constants fl_* or dr_* + + FIXME: unimplemented + """ + raise NotImplementedError + + +#---------------------------------------------------------------------------- +# F I L E I / O +#---------------------------------------------------------------------------- +def fopen(file, mode): + raise DeprecatedIDCError, "fopen() deprecated. Use Python file objects instead." + +def fclose(handle): + raise DeprecatedIDCError, "fclose() deprecated. Use Python file objects instead." + +def filelength(handle): + raise DeprecatedIDCError, "filelength() deprecated. Use Python file objects instead." + +def fseek(handle, offset, origin): + raise DeprecatedIDCError, "fseek() deprecated. Use Python file objects instead." + +def ftell(handle): + raise DeprecatedIDCError, "ftell() deprecated. Use Python file objects instead." + + +def LoadFile(filepath, pos, ea, size): + """ + Load file into IDA database + + @param filepath: path to input file + @param pos: position in the file + @param ea: linear address to load + @param size: number of bytes to load + + @return: 0 - error, 1 - ok + """ + li = idaapi.open_linput(filepath, False) + + if li: + retval = idaapi.file2base(li, pos, ea, ea+size, False) + idaapi.close_linput(li) + return retval + else: + return 0 + + +def SaveFile(filepath, pos, ea, size): + """ + Save from IDA database to file + + @param filepath: path to output file + @param pos: position in the file + @param ea: linear address to save from + @param size: number of bytes to save + + @return: 0 - error, 1 - ok + """ + of = idaapi.fopenWB(filepath) + + if of: + retval = idaapi.base2file(of, pos, ea, ea+size) + idaapi.eclose(of) + return retval + else: + return 0 + + +def fgetc(handle): + raise DeprecatedIDCError, "fgetc() deprecated. Use Python file objects instead." + +def fputc(byte, handle): + raise DeprecatedIDCError, "fputc() deprecated. Use Python file objects instead." + +def fprintf(handle, format, *args): + raise DeprecatedIDCError, "fprintf() deprecated. Use Python file objects instead." + +def readshort(handle, mostfirst): + raise DeprecatedIDCError, "readshort() deprecated. Use Python file objects instead." + +def readlong(handle, mostfirst): + raise DeprecatedIDCError, "readlong() deprecated. Use Python file objects instead." + +def writeshort(handle, word, mostfirst): + raise DeprecatedIDCError, "writeshort() deprecated. Use Python file objects instead." + +def writelong(handle, dword, mostfirst): + raise DeprecatedIDCError, "writelong() deprecated. Use Python file objects instead." + +def readstr(handle): + raise DeprecatedIDCError, "readstr() deprecated. Use Python file objects instead." + +def writestr(handle, str): + raise DeprecatedIDCError, "writestr() deprecated. Use Python file objects instead." + +# ---------------------------------------------------------------------------- +# F U N C T I O N S +# ---------------------------------------------------------------------------- + +def MakeFunction(start, end): + """ + Create a function + + @param start: function bounds + @param end: function bounds + + If the function end address is BADADDR, then + IDA will try to determine the function bounds + automatically. IDA will define all necessary + instructions to determine the function bounds. + + @return: !=0 - ok + + @note: an instruction should be present at the start address + """ + return idaapi.add_func(start, end) + + +def DelFunction(ea): + """ + Delete a function + + @param ea: any address belonging to the function + + @return: !=0 - ok + """ + return idaapi.del_func(ea) + + +def SetFunctionEnd(ea, end): + """ + Change function end address + + @param ea: any address belonging to the function + @param end: new function end address + + @return: !=0 - ok + """ + return idaapi.func_setend(ea, end) + + +def NextFunction(ea): + """ + Find next function + + @param ea: any address belonging to the function + + @return: -1 - no more functions + otherwise returns the next function start address + """ + func = idaapi.get_next_func(ea) + + if not func: + return BADADDR + else: + return func.startEA + + +def PrevFunction(ea): + """ + Find previous function + + @param ea: any address belonging to the function + + @return: -1 - no more functions + otherwise returns the previous function start address + """ + func = idaapi.get_prev_func(ea) + + if not func: + return BADADDR + else: + return func.startEA + + +def GetFunctionAttr(ea, attr): + """ + Get a function attribute + + @param ea: any address belonging to the function + @param attr: one of FUNCATTR_... constants + + @return: -1 - error otherwise returns the attribute value + """ + func = idaapi.get_func(ea) + + if func: + return _IDC_GetAttr(func, _FUNCATTRMAP, attr) + + +def SetFunctionAttr(ea, attr, value): + """ + Set a function attribute + + @param ea: any address belonging to the function + @param attr: one of FUNCATTR_... constants + @param value: new value of the attribute + + @return: 1-ok, 0-failed + """ + func = idaapi.get_func(ea) + + if func: + _IDC_SetAttr(func, _FUNCATTRMAP, attr, value) + return idaapi.update_func(func) + + +FUNCATTR_START = 0 # function start address +FUNCATTR_END = 4 # function end address +FUNCATTR_FLAGS = 8 # function flags +FUNCATTR_FRAME = 10 # function frame id +FUNCATTR_FRSIZE = 14 # size of local variables +FUNCATTR_FRREGS = 18 # size of saved registers area +FUNCATTR_ARGSIZE = 20 # number of bytes purged from the stack +FUNCATTR_FPD = 24 # frame pointer delta +FUNCATTR_COLOR = 28 # function color code + +_FUNCATTRMAP = { + FUNCATTR_START : 'startEA', + FUNCATTR_END : 'endEA', + FUNCATTR_FLAGS : 'flags', + FUNCATTR_FRAME : 'frame', + FUNCATTR_FRSIZE : 'frsize', + FUNCATTR_FRREGS : 'frregs', + FUNCATTR_ARGSIZE : 'argsize', + FUNCATTR_FPD : 'fpd', + FUNCATTR_COLOR : 'color' +} + + +def GetFunctionFlags(ea): + """ + Retrieve function flags + + @param ea: any address belonging to the function + + @return: -1 - function doesn't exist otherwise returns the flags + """ + func = idaapi.get_func(ea) + + if not func: + return -1 + else: + return func.flags + + +FUNC_NORET = idaapi.FUNC_NORET # function doesn't return +FUNC_FAR = idaapi.FUNC_FAR # far function +FUNC_LIB = idaapi.FUNC_LIB # library function +FUNC_STATIC = idaapi.FUNC_STATIC # static function +FUNC_FRAME = idaapi.FUNC_FRAME # function uses frame pointer (BP) +FUNC_USERFAR = idaapi.FUNC_USERFAR # user has specified far-ness + # of the function +FUNC_HIDDEN = idaapi.FUNC_HIDDEN # a hidden function +FUNC_THUNK = idaapi.FUNC_THUNK # thunk (jump) function +FUNC_BOTTOMBP = idaapi.FUNC_BOTTOMBP # BP points to the bottom of the stack frame + + +def SetFunctionFlags(ea, flags): + """ + Change function flags + + @param ea: any address belonging to the function + @param flags: see GetFunctionFlags() for explanations + + @return: !=0 - ok + """ + func = idaapi.get_func(ea) + + if not func: + return 0 + else: + func.flags = flags + idaapi.update_func(func) + return 1 + + +def GetFunctionName(ea): + """ + Retrieve function name + + @param ea: any address belonging to the function + + @return: null string - function doesn't exist + otherwise returns function name + """ + name = idaapi.get_func_name(ea) + + if not name: + return "" + else: + return name + + +def GetFunctionCmt(ea, repeatable): + """ + Retrieve function comment + + @param ea: any address belonging to the function + @param repeatable: 1: get repeatable comment + 0: get regular comment + + @return: function comment string + """ + func = idaapi.get_func(ea) + + if not func: + return "" + else: + comment = idaapi.get_func_cmt(func, repeatable) + + if not comment: + return "" + else: + return comment + + +def SetFunctionCmt(ea, cmt, repeatable): + """ + Set function comment + + @param ea: any address belonging to the function + @param cmt: a function comment line + @param repeatable: 1: get repeatable comment + 0: get regular comment + """ + func = idaapi.get_func(ea) + + if not func: + return None + else: + return idaapi.set_func_cmt(func, cmt, repeatable) + + +def ChooseFunction(title): + """ + Ask the user to select a function + + Arguments: + + @param title: title of the dialog box + + @return: -1 - user refused to select a function + otherwise returns the selected function start address + """ + return idaapi.choose_func(title) + + +def GetFuncOffset(ea): + """ + Convert address to 'funcname+offset' string + + @param ea - address to convert + + @return: if the address belongs to a function then return a string + formed as 'name+offset' where 'name' is a function name + 'offset' is offset within the function else return null string + """ + return idaapi.a2funcoff(ea) + + +def FindFuncEnd(ea): + """ + Determine a new function boundaries + + @param ea: starting address of a new function + + @return: if a function already exists, then return its end address. + If a function end cannot be determined, the return BADADDR + otherwise return the end address of the new function + """ + func = idaapi.func_t() + + res = idaapi.find_func_bounds(ea, func, idaapi.FIND_FUNC_DEFINE) + + if res == idaapi.FIND_FUNC_UNDEF: + return BADADDR + else: + return func.endEA + + +def GetFrame(ea): + """ + Get ID of function frame structure + + @param ea: any address belonging to the function + + @return: ID of function frame or None In order to access stack variables + you need to use structure member manipulaion functions with the + obtained ID. + """ + frame = idaapi.get_frame(ea) + + if frame: + return frame.id + else: + return None + + +def GetFrameLvarSize(ea): + """ + Get size of local variables in function frame + + @param ea: any address belonging to the function + + @return: Size of local variables in bytes. + If the function doesn't have a frame, return 0 + If the function does't exist, return None + """ + return GetFunctionAttr(ea, FUNCATTR_FRSIZE) + + +def GetFrameRegsSize(ea): + """ + Get size of saved registers in function frame + + @param ea: any address belonging to the function + + @return: Size of saved registers in bytes. + If the function doesn't have a frame, return 0 + This value is used as offset for BP (if FUNC_FRAME is set) + If the function does't exist, return None + """ + return GetFunctionAttr(ea, FUNCATTR_FRREGS) + + +def GetFrameArgsSize(ea): + """ + Get size of arguments in function frame which are purged upon return + + @param ea: any address belonging to the function + + @return: Size of function arguments in bytes. + If the function doesn't have a frame, return 0 + If the function does't exist, return -1 + """ + return GetFunctionAttr(ea, FUNCATTR_ARGSIZE) + + +def GetFrameSize(ea): + """ + Get full size of function frame + + @param ea: any address belonging to the function + @returns: Size of function frame in bytes. + This function takes into account size of local + variables + size of saved registers + size of + return address + size of function arguments + If the function doesn't have a frame, return size of + function return address in the stack. + If the function does't exist, return 0 + """ + func = idaapi.get_func(ea) + + if not func: + return 0 + else: + return idaapi.get_frame_size(func) + + +def MakeFrame(ea, lvsize, frregs, argsize): + """ + Make function frame + + @param ea: any address belonging to the function + @param lvsize: size of function local variables + @param frregs: size of saved registers + @param argsize: size of function arguments + + @return: ID of function frame or None + If the function did not have a frame, the frame + will be created. Otherwise the frame will be modified + """ + func = idaapi.get_func(ea) + + if not func: + return None + + return idaapi.add_frame(func, lvsize, frregs, argsize) + + +def GetSpd(ea): + """ + Get current delta for the stack pointer + + @param ea: end address of the instruction + i.e.the last address of the instruction+1 + + @return: The difference between the original SP upon + entering the function and SP for the specified address + """ + func = idaapi.get_func(ea) + + if not func: + return None + + return idaapi.get_spd(func, ea) + + +def GetSpDiff(ea): + """ + Get modification of SP made by the instruction + + @param ea: end address of the instruction + i.e.the last address of the instruction+1 + + @return: Get modification of SP made at the specified location + If the specified location doesn't contain a SP change point, return 0 + Otherwise return delta of SP modification + """ + func = idaapi.get_func(ea) + + if not func: + return None + + return idaapi.get_sp_delta(func, ea) + + +def SetSpDiff(ea, delta): + """ + Setup modification of SP made by the instruction + + @param ea: end address of the instruction + i.e.the last address of the instruction+1 + @param delta: the difference made by the current instruction. + + @return: 1-ok, 0-failed + """ + return idaapi.add_user_stkpnt(ea, delta) + + +# ---------------------------------------------------------------------------- +# E N T R Y P O I N T S +# ---------------------------------------------------------------------------- + +def GetEntryPointQty(): + """ + Retrieve number of entry points + + @returns: number of entry points + """ + return idaapi.get_entry_qty() + + +def AddEntryPoint(ordinal, ea, name, makecode): + """ + Add entry point + + @param ordinal: entry point number + if entry point doesn't have an ordinal + number, 'ordinal' should be equal to 'ea' + @param ea: address of the entry point + @param name: name of the entry point. If null string, + the entry point won't be renamed. + @param makecode: if 1 then this entry point is a start + of a function. Otherwise it denotes data bytes. + + @return: 0 - entry point with the specifed ordinal already exists + 1 - ok + """ + return idaapi.add_entry(ordinal, ea, name, makecode) + + +def GetEntryOrdinal(index): + """ + Retrieve entry point ordinal number + + @param index: 0..GetEntryPointQty()-1 + + @return: 0 if entry point doesn't exist + otherwise entry point ordinal + """ + return idaapi.get_entry_ordinal(index) + + +def GetEntryPoint(ordinal): + """ + Retrieve entry point address + + @param ordinal: entry point number + it is returned by GetEntryPointOrdinal() + + @return: -1 if entry point doesn't exist + otherwise entry point address. + If entry point address is equal to its ordinal + number, then the entry point has no ordinal. + """ + return idaapi.get_entry(ordinal) + + +def RenameEntryPoint(ordinal, name): + """ + Rename entry point + + @param ordinal: entry point number + @param name: new name + + @return: !=0 - ok + """ + return idaapi.rename_entry(ordinal, name) + + +# ---------------------------------------------------------------------------- +# F I X U P S +# ---------------------------------------------------------------------------- +def GetNextFixupEA(ea): + """ + Find next address with fixup information + + @param ea: current address + + @return: -1 - no more fixups otherwise returns the next + address with fixup information + """ + return idaapi.get_next_fixup_ea(ea) + + +def GetPrevFixupEA(ea): + """ + Find previous address with fixup information + + @param ea: current address + + @return: -1 - no more fixups otherwise returns the + previous address with fixup information + """ + return idaapi.get_prev_fixup_ea(ea) + + +def GetFixupTgtType(ea): + """ + Get fixup target type + + @param ea: address to get information about + + @return: -1 - no fixup at the specified address + otherwise returns fixup target type: + """ + fd = idaapi.get_fixup(ea) + + if not fd: + return -1 + + return fd.type + + +FIXUP_MASK = 0xF +FIXUP_OFF8 = 0 # 8-bit offset. +FIXUP_BYTE = FIXUP_OFF8 # 8-bit offset. +FIXUP_OFF16 = 1 # 16-bit offset. +FIXUP_SEG16 = 2 # 16-bit base--logical segment base (selector). +FIXUP_PTR32 = 3 # 32-bit long pointer (16-bit base:16-bit + # offset). +FIXUP_OFF32 = 4 # 32-bit offset. +FIXUP_PTR48 = 5 # 48-bit pointer (16-bit base:32-bit offset). +FIXUP_HI8 = 6 # high 8 bits of 16bit offset +FIXUP_HI16 = 7 # high 16 bits of 32bit offset +FIXUP_LOW8 = 8 # low 8 bits of 16bit offset +FIXUP_LOW16 = 9 # low 16 bits of 32bit offset +FIXUP_REL = 0x10 # fixup is relative to the linear address + # specified in the 3d parameter to set_fixup() +FIXUP_SELFREL = 0x0 # self-relative? + # - disallows the kernel to convert operands + # in the first pass + # - this fixup is used during output + # This type of fixups is not used anymore. + # Anyway you can use it for commenting purposes + # in the loader modules +FIXUP_EXTDEF = 0x20 # target is a location (otherwise - segment) +FIXUP_UNUSED = 0x40 # fixup is ignored by IDA + # - disallows the kernel to convert operands + # - this fixup is not used during output +FIXUP_CREATED = 0x80 # fixup was not present in the input file + + +def GetFixupTgtSel(ea): + """ + Get fixup target selector + + @param ea: address to get information about + + @return: -1 - no fixup at the specified address + otherwise returns fixup target selector + """ + fd = idaapi.get_fixup(ea) + + if not fd: + return -1 + + return fd.sel + + +def GetFixupTgtOff(ea): + """ + Get fixup target offset + + @param ea: address to get information about + + @return: -1 - no fixup at the specified address + otherwise returns fixup target offset + """ + fd = idaapi.get_fixup(ea) + + if not fd: + return -1 + + return fd.off + + +def GetFixupTgtDispl(ea): + """ + Get fixup target displacement + + @param ea: address to get information about + + @return: -1 - no fixup at the specified address + otherwise returns fixup target displacement + """ + fd = idaapi.get_fixup(ea) + + if not fd: + return -1 + + return fd.displacement + + +def SetFixup(ea, type, targetsel, targetoff, displ): + """ + Set fixup information + + @param ea: address to set fixup information about + @param type: fixup type. see GetFixupTgtType() + for possible fixup types. + @param targetsel: target selector + @param targetoff: target offset + @param displ: displacement + + @return: none + """ + fd = idaapi.fixup_data_t() + fd.type = type + fd.sel = targetsel + fd.off = targetoff + fd.displacement = displ + + idaapi.set_fixup(ea, fd) + + +def DelFixup(ea): + """ + Delete fixup information + + @param ea: address to delete fixup information about + + @return: None + """ + idaapi.del_fixup(ea) + + +#---------------------------------------------------------------------------- +# M A R K E D P O S I T I O N S +#---------------------------------------------------------------------------- + +def MarkPosition(ea, lnnum, x, y, slot, comment): + """ + Mark position + + @param ea: address to mark + @param lnnum: number of generated line for the 'ea' + @param x: x coordinate of cursor + @param y: y coordinate of cursor + @param slot: slot number: 1..1024 + if the specifed value is not within the + range, IDA will ask the user to select slot. + @param comment: description of the mark. Should be not empty. + + @return: None + """ + curloc = idaapi.curloc() + curloc.ea = ea + curloc.lnnum = lnnum + curloc.x = x + curloc.y = y + curloc.mark(slot, comment, comment) + + +def GetMarkedPos(slot): + """ + Get marked position + + @param slot: slot number: 1..1024 if the specifed value is <= 0 + range, IDA will ask the user to select slot. + + @return: -1 - the slot doesn't contain a marked address + otherwise returns the marked address + """ + curloc = idaapi.curloc() + intp = idaapi.int_pointer() + intp.assign(slot) + return curloc.markedpos(intp) + + +def GetMarkComment(slot): + """ + Get marked position comment + + @param slot: slot number: 1..1024 + + @return: None if the slot doesn't contain a marked address + otherwise returns the marked address comment + """ + curloc = idaapi.curloc() + return curloc.markdesc(slot) + + +# ---------------------------------------------------------------------------- +# S T R U C T U R E S +# ---------------------------------------------------------------------------- + +def GetStrucQty(): + """ + Get number of defined structure types + + @return: number of structure types + """ + return idaapi.get_struc_qty() + + +def GetFirstStrucIdx(): + """ + Get index of first structure type + + @return: -1 if no structure type is defined + index of first structure type. + Each structure type has an index and ID. + INDEX determines position of structure definition + in the list of structure definitions. Index 1 + is listed first, after index 2 and so on. + The index of a structure type can be changed any + time, leading to movement of the structure definition + in the list of structure definitions. + ID uniquely denotes a structure type. A structure + gets a unique ID at the creation time and this ID + can't be changed. Even when the structure type gets + deleted, its ID won't be resued in the future. + """ + return idaapi.get_first_struc_idx() + + +def GetLastStrucIdx(): + """ + Get index of last structure type + + @return: -1 if no structure type is defined + index of last structure type. + See GetFirstStrucIdx() for the explanation of + structure indices and IDs. + """ + return idaapi.get_last_struc_idx() + + +def GetNextStrucIdx(index): + """ + Get index of next structure type + + @param index: current structure index + + @return: -1 if no (more) structure type is defined + index of the next structure type. + See GetFirstStrucIdx() for the explanation of + structure indices and IDs. + """ + return idaapi.get_next_struc_idx(index) + + +def GetPrevStrucIdx(index): + """ + Get index of previous structure type + + @param index: current structure index + + @return: -1 if no (more) structure type is defined + index of the presiouvs structure type. + See GetFirstStrucIdx() for the explanation of + structure indices and IDs. + """ + return idaapi.get_prev_struc_idx(index) + + +def GetStrucIdx(id): + """ + Get structure index by structure ID + + @param id: structure ID + + @return: -1 if bad structure ID is passed + otherwise returns structure index. + See GetFirstStrucIdx() for the explanation of + structure indices and IDs. + """ + return idaapi.get_struc_idx(id) + + +def GetStrucId(index): + """ + Get structure ID by structure index + + @param index: structure index + + @return: -1 if bad structure index is passed otherwise returns structure ID. + + @note: See GetFirstStrucIdx() for the explanation of structure indices and IDs. + """ + return idaapi.get_struc_by_idx(index) + + +def GetStrucIdByName(name): + """ + Get structure ID by structure name + + @param name: structure type name + + @return: -1 if bad structure type name is passed + otherwise returns structure ID. + """ + return idaapi.get_struc_id(name) + + +def GetStrucName(id): + """ + Get structure type name + + @param id: structure type ID + + @return: -1 if bad structure type ID is passed + otherwise returns structure type name. + """ + return idaapi.get_struc_name(id) + + +def GetStrucComment(id, repeatable): + """ + Get structure type comment + + @param id: structure type ID + @param repeatable: 1: get repeatable comment + 0: get regular comment + + @return: None if bad structure type ID is passed + otherwise returns comment. + """ + return idaapi.get_struc_cmt(id, repeatable) + + +def GetStrucSize(id): + """ + Get size of a structure + + @param id: structure type ID + + @return: -1 if bad structure type ID is passed + otherwise returns size of structure in bytes. + """ + return idaapi.get_struc_size(id) + + +def GetMemberQty(id): + """ + Get number of members of a structure + + @param id: structure type ID + + @return: -1 if bad structure type ID is passed otherwise + returns number of members. + """ + s = idaapi.get_struc(id) + if not s: + return -1 + + return s.memqty + + +def GetStrucPrevOff(id, offset): + """ + Get previous offset in a structure + + @param id: structure type ID + @param offset: current offset + + @return: -1 if bad structure type ID is passed + or no (more) offsets in the structure + otherwise returns previous offset in a structure. + + @note: IDA allows 'holes' between members of a + structure. It treats these 'holes' + as unnamed arrays of bytes. + This function returns a member offset or a hole offset. + It will return size of the structure if input + 'offset' is bigger than the structure size. + """ + s = idaapi.get_struc(id) + if not s: + return -1 + + return idaapi.get_struc_prev_offset(s, offset) + + +def GetStrucNextOff(id, offset): + """ + Get next offset in a structure + + @param id: structure type ID + @param offset: current offset + + @return: -1 if bad structure type ID is passed + or no (more) offsets in the structure + otherwise returns next offset in a structure. + + @note: IDA allows 'holes' between members of a + structure. It treats these 'holes' + as unnamed arrays of bytes. + This function returns a member offset or a hole offset. + It will return size of the structure if input + 'offset' belongs to the last member of the structure. + """ + s = idaapi.get_struc(id) + if not s: + return -1 + + return idaapi.get_struc_next_offset(s, offset) + + +def GetFirstMember(id): + """ + Get offset of the first member of a structure + + @param id: structure type ID + + @return: -1 if bad structure type ID is passed + or structure has no members + otherwise returns offset of the first member. + + @note: IDA allows 'holes' between members of a + structure. It treats these 'holes' + as unnamed arrays of bytes. + """ + s = idaapi.get_struc(id) + if not s: + return -1 + + return idaapi.get_struc_first_offset(s, offset) + + +def GetLastMember(id): + """ + Get offset of the last member of a structure + + @param id: structure type ID + + @return: -1 if bad structure type ID is passed + or structure has no members + otherwise returns offset of the last member. + + @note: IDA allows 'holes' between members of a + structure. It treats these 'holes' + as unnamed arrays of bytes. + """ + s = idaapi.get_struc(id) + if not s: + return -1 + + return idaapi.get_struc_last_offset(s, offset) + + +def GetMemberOffset(id, member_name): + """ + Get offset of a member of a structure by the member name + + @param id: structure type ID + @param member_name: name of structure member + + @return: -1 if bad structure type ID is passed + or no such member in the structure + otherwise returns offset of the specified member. + """ + s = idaapi.get_struc(id) + if not s: + return -1 + + m = idaapi.get_member_by_name(s, member_name) + if not m: + return -1 + + return m.get_soff() + + +def GetMemberName(id, member_offset): + """ + Get name of a member of a structure + + @param id: structure type ID + @param member_offset: member offset. The offset can be + any offset in the member. For example, + is a member is 4 bytes long and starts + at offset 2, then 2,3,4,5 denote + the same structure member. + + @return: None if bad structure type ID is passed + or no such member in the structure + otherwise returns name of the specified member. + """ + s = idaapi.get_struc(id) + if not s: + return None + + m = idaapi.get_member(s, member_offset) + if not m: + return None + + return idaapi.get_member_name(m.id) + + +def GetMemberComment(id, member_offset, repeatable): + """ + Get comment of a member + + @param id: structure type ID + @param member_offset: member offset. The offset can be + any offset in the member. For example, + is a member is 4 bytes long and starts + at offset 2, then 2,3,4,5 denote + the same structure member. + @param repeatable: 1: get repeatable comment + 0: get regular comment + + @return: None if bad structure type ID is passed + or no such member in the structure + otherwise returns comment of the specified member. + """ + s = idaapi.get_struc(id) + if not s: + return None + + m = idaapi.get_member(s, member_offset) + if not m: + return None + + return idaapi.get_member_cmt(m.id, repeatable) + + +def GetMemberSize(id, member_offset): + """ + Get size of a member + + @param id: structure type ID + @param member_offset: member offset. The offset can be + any offset in the member. For example, + is a member is 4 bytes long and starts + at offset 2, then 2,3,4,5 denote + the same structure member. + + @return: -1 if bad structure type ID is passed + or no such member in the structure + otherwise returns size of the specified + member in bytes. + """ + s = idaapi.get_struc(id) + if not s: + return None + + m = idaapi.get_member(s, member_offset) + if not m: + return None + + return idaapi.get_member_size(m) + + +def GetMemberFlag(id, member_offset): + """ + Get type of a member + + @param id: structure type ID + @param member_offset: member offset. The offset can be + any offset in the member. For example, + is a member is 4 bytes long and starts + at offset 2, then 2,3,4,5 denote + the same structure member. + + @return: -1 if bad structure type ID is passed + or no such member in the structure + otherwise returns type of the member, see bit + definitions above. If the member type is a structure + then function GetMemberStrid() should be used to + get the structure type id. + """ + s = idaapi.get_struc(id) + if not s: + return -1 + + m = idaapi.get_member(s, member_offset) + if not m: + return -1 + + return m.flag + + +def GetMemberStrId(id, member_offset): + """ + Get structure id of a member + + @param id: structure type ID + @param member_offset: member offset. The offset can be + any offset in the member. For example, + is a member is 4 bytes long and starts + at offset 2, then 2,3,4,5 denote + the same structure member. + @return: -1 if bad structure type ID is passed + or no such member in the structure + otherwise returns structure id of the member. + If the current member is not a structure, returns -1. + """ + s = idaapi.get_struc(id) + if not s: + return -1 + + m = idaapi.get_member(s, member_offset) + if not m: + return -1 + + cs = get_member_struc(m) + if cs: + return cs.id + else: + return -1 + + +def IsUnion(id): + """ + Is a structure a union? + + @param id: structure type ID + + @return: 1: yes, this is a union id + 0: no + + @note: Unions are a special kind of structures + """ + s = idaapi.get_struc(id) + if not s: + return 0 + + return s.is_union() + + +def AddStrucEx(index, name, is_union): + """ + Define a new structure type + + @param index: index of new structure type + If another structure has the specified index, + then index of that structure and all other + structures will be incremented, freeing the specifed + index. If index is == -1, then the biggest index + number will be used. + See GetFirstStrucIdx() for the explanation of + structure indices and IDs. + @param name: name of the new structure type. + @param is_union: 0: structure + 1: union + + @return: -1 if can't define structure type because of + bad structure name: the name is ill-formed or is + already used in the program. + otherwise returns ID of the new structure type + """ + if index == -1: + index = BADADDR + + return idaapi.add_struc(index, name, is_union) + + +def DelStruc(id): + """ + Delete a structure type + + @param id: structure type ID + + @return: 0 if bad structure type ID is passed + 1 otherwise the structure type is deleted. All data + and other structure types referencing to the + deleted structure type will be displayed as array + of bytes. + """ + s = idaapi.get_struc(id) + if not s: + return 0 + + return idaapi.del_struc(s) + + +def SetStrucIdx(id, index): + """ + Change structure index + + @param id: structure type ID + @param index: new index of the structure + + @return: != 0 - ok + + @note: See GetFirstStrucIdx() for the explanation of + structure indices and IDs. + """ + s = idaapi.get_struc(id) + if not s: + return 0 + + return idaapi.set_struc_idx(s, index) + + +def SetStrucName(id, name): + """ + Change structure name + + @param id: structure type ID + @param name: new name of the structure + + @return: != 0 - ok + """ + return idaapi.set_struc_name(id, name) + + +def SetStrucComment(id, comment, repeatable): + """ + Change structure comment + + @param id: structure type ID + @param comment: new comment of the structure + @param repeatable: 1: change repeatable comment + 0: change regular comment + @return: != 0 - ok + """ + return idaapi.set_struc_cmt(id, comment, repeatable) + + +def _IDC_PrepareStrucMemberTypeinfo(flag, typeid): + """ Internal function to prepare typeinfo_t for adding/setting structure members """ + + simple_types = [ FF_BYTE, FF_WORD, FF_DWRD, FF_QWRD, FF_OWRD, FF_TBYT, FF_FLOAT, FF_DOUBLE, FF_PACKREAL ] + + if idaapi.isASCII(flag): + ti = idaapi.typeinfo_t() + ti.strtype = typeid + elif idaapi.isStruct(flag): + ti = idaapi.typeinfo_t() + ti.tid = typeid + elif idaapi.isOff0(flag): + ti = idaapi.typeinfo_t() + ri = idaapi.refinfo_t() + ri.base = typeid + ti.ri = ri + elif idaapi.isEnum0(flag): + ti = idaapi.typeinfo_t() + ec = idaapi.enum_const_t() + ec.tid = typeid + ti.ec = ec + elif idaapi.isStroff0(flag): + ti = idaapi.typeinfo_t() + ti.path.len = 2 + target_struct = idaapi.get_struc(typeid) + assert target_struct, "Target structure is invalid" + target_member = idaapi.get_member(target_struct, 0) + assert target_member, "Target member is not found" + ti.path.ids = [ typeid, target_member.id ] + elif ((flag & 0xFFFFFF) & idaapi.DT_TYPE) in simple_types: + ti = None + else: + assert False, "Unknown type flag 0x%08x" % flag + return ti + + +def AddStrucMember(id, name, offset, flag, typeid, nbytes): + """ + Add structure member + + @param id: structure type ID + @param name: name of the new member + @param offset: offset of the new member + -1 means to add at the end of the structure + @param flag: type of the new member. Should be one of + FF_BYTE..FF_PACKREAL (see above) combined with FF_DATA + @param typeid: structure id if 'flag' == FF_STRU + Denotes type of the member if the member itself is a structure. + if isOff0(flag) then typeid specifies the offset base. + if isASCII(flag) then typeid specifies the string type (ASCSTR_...). + if isStroff(flag) then typeid specifies the structure id + Otherwise should be -1. + @param nbytes: number of bytes in the new member + + @return: 0 - ok, otherwise error code (one of STRUC_ERROR_*) + """ + struc = idaapi.get_struc(id) + assert struct, "get_struc() failed" + ti = _IDC_PrepareStrucMemberTypeinfo(flag, typeid) + return idaapi.add_struc_member(struc, name, offset, flag, ti, nbytes) + + +STRUC_ERROR_MEMBER_NAME = -1 # already has member with this name (bad name) +STRUC_ERROR_MEMBER_OFFSET = -2 # already has member at this offset +STRUC_ERROR_MEMBER_SIZE = -3 # bad number of bytes or bad sizeof(type) +STRUC_ERROR_MEMBER_TINFO = -4 # bad typeid parameter +STRUC_ERROR_MEMBER_STRUCT = -5 # bad struct id (the 1st argument) +STRUC_ERROR_MEMBER_UNIVAR = -6 # unions can't have variable sized members +STRUC_ERROR_MEMBER_VARLAST = -7 # variable sized member should be the last member in the structure + + +def DelStrucMember(id, member_offset): + """ + Delete structure member + + @param id: structure type ID + @param member_offset: offset of the member + + @return: != 0 - ok. + + @note: IDA allows 'holes' between members of a + structure. It treats these 'holes' + as unnamed arrays of bytes. + """ + s = idaapi.get_struc(id) + if not s: + return 0 + + return idaapi.del_struc_member(s, member_offset) + + +def SetMemberName(id, member_offset, name): + """ + Change structure member name + + @param id: structure type ID + @param member_offset: offset of the member + @param name: new name of the member + + @return: != 0 - ok. + """ + s = idaapi.get_struc(id) + if not s: + return 0 + + return idaapi.set_member_name(s, member_offset, name) + + +def SetMemberType(id, member_offset, flag, typeid, nitems): + """ + Change structure member type + + @param id: structure type ID + @param member_offset: offset of the member + @param flag: new type of the member. Should be one of + FF_BYTE..FF_PACKREAL (see above) combined with FF_DATA + @param typeid: structure id if 'flag' == FF_STRU + Denotes type of the member is the member + itself is a structure. Otherwise should be -1. + if isOff0(flag) then typeid specifies the offset base. + if isASCII(flag) then typeid specifies the string type + (ASCSTR_...). + @param nitems: number of items in the member + + @return: !=0 - ok. + """ + struc = idaapi.get_struc(id) + assert struct, "get_struc() failed" + ti = _IDC_PrepareStrucMemberTypeinfo(flag, typeid) + return idaapi.set_member_type(struc, member_offset, flag, ti, nitems) + + +def SetMemberComment(id, member_offset, comment, repeatable): + """ + Change structure member comment + + @param id: structure type ID + @param member_offset: offset of the member + @param comment: new comment of the structure member + @param repeatable: 1: change repeatable comment + 0: change regular comment + + @return: != 0 - ok + """ + s = idaapi.get_struc(id) + if not s: + return 0 + + m = idaapi.get_member(s, member_offset) + if not m: + return 0 + + return idaapi.set_member_cmt(m, comment, repeatable) + + +def GetFchunkAttr(ea, attr): + """ + Get a function chunk attribute + + @param ea: any address in the chunk + @param attr: one of: FUNCATTR_START, FUNCATTR_END, FUNCATTR_COLOR + + @return: desired attribute or -1 + """ + if attr in [ FUNCATTR_START, FUNCATTR_END, FUNCATTR_COLOR ]: + return GetFunctionAttr(ea, attr) + else: + return -1 + + +def SetFchunkAttr(ea, attr, value): + """ + Set a function chunk attribute + + @param ea: any address in the chunk + @param attr: only FUNCATTR_COLOR + @param value: desired bg color (RGB) + + @return: 0 if failed, 1 if success + """ + if attr in [ FUNCATTR_COLOR ]: + return SetFunctionAttr(ea, attr, value) + else: + return 0 + + +def NextFchunk(ea): + """ + Get next function chunk + + @param ea: any address + + @return: the starting address of the next function chunk or BADADDR + + @note: This function enumerates all chunks of all functions in the database + """ + func = idaapi.get_next_fchunk(ea) + + if func: + return func.startEA + else: + return BADADDR + + +def PrevFchunk(ea): + """ + Get previous function chunk + + @param ea: any address + + @return: the starting address of the function chunk or BADADDR + + @note: This function enumerates all chunks of all functions in the database + """ + func = idaapi.get_prev_fchunk(ea) + + if func: + return func.startEA + else: + return BADADDR + + +def AppendFchunk(funcea, ea1, ea2): + """ + Append a function chunk to the function + + @param funcea: any address in the function + @param ea1: start of function tail + @param ea2: end of function tail + @return: 0 if failed, 1 if success + + @note: If a chunk exists at the specified addresses, it must have exactly + the specified boundaries + """ + func = idaapi.get_func(funcea) + + if not func: + return 0 + else: + return idaapi.append_func_tail(func, ea1, ea2) + + +def RemoveFchunk(funcea, tailea): + """ + Remove a function chunk from the function + + @param funcea: any address in the function + @param ea1: any address in the function chunk to remove + + @return: 0 if failed, 1 if success + """ + func = idaapi.get_func(funcea) + + if not func: + return 0 + else: + return idaapi.remove_func_tail(func, tailea) + + +def SetFchunkOwner(tailea, funcea): + """ + Change the function chunk owner + + @param tailea: any address in the function chunk + @param funcea: the starting address of the new owner + + @return: 0 if failed, 1 if success + + @note: The new owner must already have the chunk appended before the call + """ + tail = idaapi.get_func(tailea) + + if not tail: + return 0 + else: + return idaapi.set_tail_owner(tail, funcea) + + +def FirstFuncFchunk(funcea): + """ + Get the first function chunk of the specified function + + @param funcea: any address in the function + + @return: the function entry point or BADADDR + + @note: This function returns the first (main) chunk of the specified function + + FIXME: unimplemented + """ + raise NotImplementedError + + +def NextFuncFchunk(funcea, tailea): + """ + Get the next function chunk of the specified function + + @param funcea: any address in the function + @param tailea: any address in the current chunk + + @return: the starting address of the next function chunk or BADADDR + + @note: This function returns the next chunk of the specified function + + FIXME: unimplemented + """ + raise NotImplementedError + + +# ---------------------------------------------------------------------------- +# E N U M S +# ---------------------------------------------------------------------------- +def GetEnumQty(): + """ + Get number of enum types + + @return: number of enumerations + """ + return idaapi.get_enum_qty() + + +def GetnEnum(idx): + """ + Get ID of the specified enum by its serial number + + @param idx: number of enum (0..GetEnumQty()-1) + + @return: ID of enum or -1 if error + """ + return idaapi.getn_enum(idx) + + +def GetEnumIdx(enum_id): + """ + Get serial number of enum by its ID + + @param enum_id: ID of enum + + @return: (0..GetEnumQty()-1) or -1 if error + """ + return idaapi.get_enum_idx(enum_id) + + +def GetEnum(name): + """ + Get enum ID by the name of enum + + Arguments: + name - name of enum + + returns: ID of enum or -1 if no such enum exists + """ + return idaapi.get_enum(name) + + +def GetEnumName(enum_id): + """ + Get name of enum + + @param enum_id: ID of enum + + @return: name of enum or empty string + """ + return idaapi.get_enum_name(enum_id) + + +def GetEnumCmt(enum_id, repeatable): + """ + Get comment of enum + + @param enum_id: ID of enum + @param repeatable: 0:get regular comment + 1:get repeatable comment + + @return: comment of enum + """ + return idaapi.get_enum_cmt(enum_id, repeatable) + + +def GetEnumSize(enum_id): + """ + Get size of enum + + @param enum_id: ID of enum + + @return: number of constants in the enum + Returns 0 if enum_id is bad. + """ + return idaapi.get_enum_size(enum_id) + + +def GetEnumFlag(enum_id): + """ + Get flag of enum + + @param enum_id: ID of enum + + @return: flags of enum. These flags determine representation + of numeric constants (binary,octal,decimal,hex) + in the enum definition. See start of this file for + more information about flags. + Returns 0 if enum_id is bad. + """ + return idaapi.get_enum_flag(enum_id) + + +def GetConstByName(name): + """ + Get member of enum - a symbolic constant ID + + @param name: name of symbolic constant + + @return: ID of constant or -1 + """ + return idaapi.get_const_by_name(name) + + +def GetConstValue(const_id): + """ + Get value of symbolic constant + + @param const_id: id of symbolic constant + + @return: value of constant or 0 + """ + return idaapi.get_const_value(const_id) + + +def GetConstBmask(const_id): + """ + Get bit mask of symbolic constant + + @param const_id: id of symbolic constant + + @return: bitmask of constant or 0 + ordinary enums have bitmask = -1 + """ + return idaapi.get_const_bitmask(const_id) + + +def GetConstEnum(const_id): + """ + Get id of enum by id of constant + + @param const_id: id of symbolic constant + + @return: id of enum the constant belongs to. + -1 if const_id is bad. + """ + return idaapi.get_const_enum(const_id) + + +def GetConstEx(enum_id, value, serial, bmask): + """ + Get id of constant + + @param enum_id: id of enum + @param value: value of constant + @param serial: serial number of the constant in the + enumeration. See OpEnumEx() for details. + @param bmask: bitmask of the constant + ordinary enums accept only -1 as a bitmask + + @return: id of constant or -1 if error + """ + return idaapi.get_const(enum_id, value, serial, bmask) + + +def GetFirstBmask(enum_id): + """ + Get first bitmask in the enum (bitfield) + + @param enum_id: id of enum (bitfield) + + @return: the smallest bitmask of constant or -1 + no bitmasks are defined yet + All bitmasks are sorted by their values + as unsigned longs. + """ + return idaapi.get_first_bmask(enum_id) + + +def GetLastBmask(enum_id): + """ + Get last bitmask in the enum (bitfield) + + @param enum_id: id of enum + + @return: the biggest bitmask or -1 no bitmasks are defined yet + All bitmasks are sorted by their values as unsigned longs. + """ + return idaapi.get_last_bmask(enum_id) + + +def GetNextBmask(enum_id, value): + """ + Get next bitmask in the enum (bitfield) + + @param enum_id: id of enum + @param value: value of the current bitmask + + @return: value of a bitmask with value higher than the specified + value. -1 if no such bitmasks exist. + All bitmasks are sorted by their values + as unsigned longs. + """ + return idaapi.get_next_bmask(enum_id, value) + + +def GetPrevBmask(enum_id, value): + """ + Get prev bitmask in the enum (bitfield) + + @param enum_id: id of enum + @param value: value of the current bitmask + + @return: value of a bitmask with value lower than the specified + value. -1 no such bitmasks exist. + All bitmasks are sorted by their values as unsigned longs. + """ + return idaapi.get_prev_bmask(enum_id, value) + + +def GetBmaskName(enum_id, bmask): + """ + Get bitmask name (only for bitfields) + + @param enum_id: id of enum + @param bmask: bitmask of the constant + + @return: name of bitmask or None + """ + return idaapi.get_bmask_name(enum_id, bmask) + + +def GetBmaskCmt(enum_id, bmask, repeatable): + """ + Get bitmask comment (only for bitfields) + + @param enum_id: id of enum + @param bmask: bitmask of the constant + @param repeatable: type of comment, 0-regular, 1-repeatable + + @return: comment attached to bitmask or None + """ + return idaapi.get_bmask_cmt(enum_id, bmask, repeatable) + + +def SetBmaskName(enum_id, bmask, name): + """ + Set bitmask name (only for bitfields) + + @param enum_id: id of enum + @param bmask: bitmask of the constant + @param name: name of bitmask + + @return: 1-ok, 0-failed + """ + return idaapi.set_bmask_name(enum_id, bmask, name) + + +def SetBmaskCmt(enum_id, bmask, cmt, repeatable): + """ + Set bitmask comment (only for bitfields) + + @param enum_id: id of enum + @param bmask: bitmask of the constant + @param cmt: comment + repeatable - type of comment, 0-regular, 1-repeatable + + @return: 1-ok, 0-failed + """ + return idaapi.set_bmask_cmt(enum_id, bmask, cmt, repeatable) + + +def GetFirstConst(enum_id, bmask): + """ + Get first constant in the enum + + @param enum_id: id of enum + @param bmask: bitmask of the constant (ordinary enums accept only -1 as a bitmask) + + @return: value of constant or -1 no constants are defined + All constants are sorted by their values as unsigned longs. + """ + return idaapi.get_first_const(enum_id, bmask) + + +def GetLastConst(enum_id, bmask): + """ + Get last constant in the enum + + @param enum_id: id of enum + @param bmask: bitmask of the constant (ordinary enums accept only -1 as a bitmask) + + @return: value of constant or -1 no constants are defined + All constants are sorted by their values + as unsigned longs. + """ + return idaapi.get_last_const(enum_id, bmask) + + +def GetNextConst(enum_id, value, bmask): + """ + Get next constant in the enum + + @param enum_id: id of enum + @param bmask: bitmask of the constant ordinary enums accept only -1 as a bitmask + @param value: value of the current constant + + @return: value of a constant with value higher than the specified + value. -1 no such constants exist. + All constants are sorted by their values as unsigned longs. + """ + return idaapi.get_next_const(enum_id, value, bmask) + + +def GetPrevConst(enum_id, value, bmask): + """ + Get prev constant in the enum + + @param enum_id: id of enum + @param bmask : bitmask of the constant + ordinary enums accept only -1 as a bitmask + @param value: value of the current constant + + @return: value of a constant with value lower than the specified + value. -1 no such constants exist. + All constants are sorted by their values as unsigned longs. + """ + return idaapi.get_prev_const(enum_id, value, bmask) + + +def GetConstName(const_id): + """ + Get name of a constant + + @param const_id: id of const + + Returns: name of constant + """ + name = idaapi.get_const_name(const_id) + + if not name: + return "" + else: + return name + + +def GetConstCmt(const_id, repeatable): + """ + Get comment of a constant + + @param const_id: id of const + @param repeatable: 0:get regular comment, 1:get repeatable comment + + @return: comment string + """ + cmt = idaapi.get_const_cmt(const_id, repeatable) + + if not cmt: + return "" + else: + return cmt + + +def AddEnum(idx, name, flag): + """ + Add a new enum type + + @param idx: serial number of the new enum. + If another enum with the same serial number + exists, then all enums with serial + numbers >= the specified idx get their + serial numbers incremented (in other words, + the new enum is put in the middle of the list of enums). + + If idx >= GetEnumQty() or idx == -1 + then the new enum is created at the end of + the list of enums. + @param name: name of the enum. + @param flag: flags for representation of numeric constants + in the definition of enum. + + @return: id of new enum or -1. + """ + return idaapi.add_enum(idx, name, flag) + + +def DelEnum(enum_id): + """ + Delete enum type + + @param enum_id: id of enum + + @return: None + """ + idaapi.del_enum(enum_id) + + +def SetEnumIdx(enum_id, idx): + """ + Give another serial number to a enum + + @param enum_id: id of enum + @param idx: new serial number. + If another enum with the same serial number + exists, then all enums with serial + numbers >= the specified idx get their + serial numbers incremented (in other words, + the new enum is put in the middle of the list of enums). + + If idx >= GetEnumQty() then the enum is + moved to the end of the list of enums. + + @return: comment string + """ + return idaapi.set_enum_idx(enum_id, idx) + + +def SetEnumName(enum_id, name): + """ + Rename enum + + @param enum_id: id of enum + @param name: new name of enum + + @return: 1-ok,0-failed + """ + return idaapi.set_enum_name(enum_id, name) + + +def SetEnumCmt(enum_id, cmt, repeatable): + """ + Set comment of enum + + @param enum_id: id of enum + @param cmt: new comment for the enum + @param repeatable: is the comment repeatable? + - 0:set regular comment + - 1:set repeatable comment + + @return: 1-ok,0-failed + """ + return idaapi.set_enum_cmt(enum_id, cmt, repeatable) + + +def SetEnumFlag(enum_id, flag): + """ + Set flag of enum + + @param enum_id: id of enum + @param flag: flags for representation of numeric constants + in the definition of enum. + + @return: 1-ok,0-failed + """ + return idaapi.set_enum_flag(enum_id, flag) + + +def SetEnumBf(enum_id, flag): + """ + Set bitfield property of enum + + @param enum_id: id of enum + @param flag: flags + - 1: convert to bitfield + - 0: convert to ordinary enum + + @return: 1-ok,0-failed + """ + return idaapi.set_enum_bf(enum_id, flag) + + +def IsBitfield(enum_id): + """ + Is enum a bitfield? + + @param enum_id: id of enum + + @return: 1-yes, 0-no, ordinary enum + """ + return idaapi.is_bf(enum_id) + + +def AddConstEx(enum_id, name, value, bmask): + """ + Add a member of enum - a symbolic constant + + @param enum_id: id of enum + @param name: name of symbolic constant. Must be unique in the program. + @param value: value of symbolic constant. + @param bmask: bitmask of the constant + ordinary enums accept only -1 as a bitmask + all bits set in value should be set in bmask too + + @return: 0-ok, otherwise error code (one of CONST_ERROR_*) + """ + return idaapi.add_const(enum_id, name, value, bmask) + + +CONST_ERROR_NAME = idaapi.CONST_ERROR_NAME # already have member with this name (bad name) +CONST_ERROR_VALUE = idaapi.CONST_ERROR_VALUE # already have member with this value +CONST_ERROR_ENUM = idaapi.CONST_ERROR_ENUM # bad enum id +CONST_ERROR_MASK = idaapi.CONST_ERROR_MASK # bad bmask +CONST_ERROR_ILLV = idaapi.CONST_ERROR_ILLV # bad bmask and value combination (~bmask & value != 0) + + +def DelConstEx(enum_id, value, serial, bmask): + """ + Delete a member of enum - a symbolic constant + + @param enum_id: id of enum + @param value: value of symbolic constant. + @param serial: serial number of the constant in the + enumeration. See OpEnumEx() for for details. + @param bmask: bitmask of the constant ordinary enums accept + only -1 as a bitmask + + @return: 1-ok, 0-failed + """ + return idaapi.del_const(enum_id, value, serial, bmask) + + +def SetConstName(const_id, name): + """ + Rename a member of enum - a symbolic constant + + @param const_id: id of const + @param name: new name of constant + + @return: 1-ok, 0-failed + """ + return idaapi.set_const_name(const_id, name) + + +def SetConstCmt(const_id, cmt, repeatable): + """ + Set a comment of a symbolic constant + + @param const_id: id of const + @param cmt: new comment for the constant + @param repeatable: is the comment repeatable? + 0: set regular comment + 1: set repeatable comment + + @return: 1-ok, 0-failed + """ + return idaapi.set_const_cmt(const_id, cmt, repeatable) + +#---------------------------------------------------------------------------- +# A R R A Y S I N I D C +#---------------------------------------------------------------------------- + +def CreateArray(name): + raise DeprecatedIDCError, "Use python pickles instead." + +def GetArrayId(name): + raise DeprecatedIDCError, "Use python pickles instead." + +def RenameArray(id, newname): + raise DeprecatedIDCError, "Use python pickles instead." + +def DeleteArray(id): + raise DeprecatedIDCError, "Use python pickles instead." + +def SetArrayLong(id, idx, value): + raise DeprecatedIDCError, "Use python pickles instead." + +def SetArrayString(id, idx, str): + raise DeprecatedIDCError, "Use python pickles instead." + +def GetArrayElement(tag, id, idx): + raise DeprecatedIDCError, "Use python pickles instead." + +def DelArrayElement(tag, id, idx): + raise DeprecatedIDCError, "Use python pickles instead." + +def GetFirstIndex(tag, id): + raise DeprecatedIDCError, "Use python pickles instead." + +def GetLastIndex(tag, id): + raise DeprecatedIDCError, "Use python pickles instead." + +def GetNextIndex(tag, id, idx): + raise DeprecatedIDCError, "Use python pickles instead." + +def GetPrevIndex(tag, id, idx): + raise DeprecatedIDCError, "Use python pickles instead." + +def SetHashLong(id, idx, value): + raise DeprecatedIDCError, "Use python pickles instead." + +def SetHashString(id, idx, value): + raise DeprecatedIDCError, "Use python pickles instead." + +def GetHashLong(id, idx): + raise DeprecatedIDCError, "Use python pickles instead." + +def GetHashString(id, idx): + raise DeprecatedIDCError, "Use python pickles instead." + +def DelHashElement(id, idx): + raise DeprecatedIDCError, "Use python pickles instead." + +def GetFirstHashKey(id): + raise DeprecatedIDCError, "Use python pickles instead." + +def GetNextHashKey(id, idx): + raise DeprecatedIDCError, "Use python pickles instead." + +def GetLastHashKey(id): + raise DeprecatedIDCError, "Use python pickles instead." + +def GetPrevHashKey(id, idx): + raise DeprecatedIDCError, "Use python pickles instead." + + +#---------------------------------------------------------------------------- +# S O U R C E F I L E / L I N E N U M B E R S +#---------------------------------------------------------------------------- +def AddSourceFile(ea1, ea2, filename): + """ + Mark a range of address as belonging to a source file + An address range may belong only to one source file. + A source file may be represented by several address ranges. + + @param ea1: linear address of start of the address range + @param ea2: linear address of end of the address range + @param filename: name of source file. + + @return: 1-ok, 0-failed. + + @note: IDA can keep information about source files used to create the program. + Each source file is represented by a range of addresses. + A source file may contains several address ranges. + """ + return idaapi.add_sourcefile(ea1, ea2, filename) + + +def GetSourceFile(ea): + """ + Get name of source file occupying the given address + + @param ea: linear address + + @return: NULL - source file information is not found + otherwise returns pointer to file name + """ + return idaapi.get_sourcefile(ea) + + +def DelSourceFile(ea): + """ + Delete information about the source file + + @param ea: linear address belonging to the source file + + @return: NULL - source file information is not found + otherwise returns pointer to file name + """ + return idaapi.del_sourcefile(ea) + + +def SetLineNumber(ea, lnnum): + """ + Set source line number + + @param ea: linear address + @param lnnum: number of line in the source file + + @return: None + """ + idaapi.set_source_linnum(ea, lnnum) + + +def GetLineNumber(ea): + """ + Get source line number + + @param ea: linear address + + @return: number of line in the source file or -1 + """ + return idaapi.get_source_linnum(ea) + + +def DelLineNumber(ea): + """ + Delete information about source line number + + @param ea: linear address + + @return: None + """ + idaapi.del_source_linnum(ea) + + +#---------------------------------------------------------------------------- +# T Y P E L I B R A R I E S +#---------------------------------------------------------------------------- + +def LoadTil(name, tildir=None): + """ + Load a type library + + @param name: name of type library. + @param tildir: drectory to load the TIL from (defaults to "til/pc") + + @return: 1-ok, 0-failed. + """ + if not tildir: + tildir = "til" + os.sep + "pc" + + til = idaapi.load_til(tildir, name) + + if til: + return 1 + else: + return 0 + + +def Til2Idb(idx, type_name): + """ + Copy information from type library to database + Copy structure, union, or enum definition from the type library + to the IDA database. + + @param idx: the position of the new type in the list of + types (structures or enums) -1 means at the end of the list + @param type_name: name of type to copy + + @return: BADNODE-failed, otherwise the type id (structure id or enum id) + """ + return idaapi.til2idb(idx, type_name) + + +def GetType(ea): + """ + Get type of function/variable + + @param ea: the address of the object + + @return: type string, 0 - failed + + FIXME: unimplemented + """ + raise NotImplementedError + + +def GuessType(ea): + """ + Guess type of function/variable + + @param ea: the address of the object, can be the structure member id too + + @return: type string, 0 - failed + + FIXME: unimplemented + """ + raise NotImplementedError + + +def SetType(ea, type): + """ + Set type of function/variable + + @param ea: the address of the object + @param type: the type string in C declaration form. + Must contain the closing ';' + if specified as an empty string, then the + assciated with 'ea' will be deleted + + @return: 1-ok, 0-failed. + + FIXME: unimplemented + """ + raise NotImplementedError + + +def ParseTypes(input, flags): + """ + Parse type declarations + + @param input: file name or C declarations (depending on the flags) + @param flags: combination of PT_... constants or 0 + + @return: number of errors + + FIXME: unimplemented + """ + raise NotImplementedError + + +PT_FILE = 0x0001 # input if a file name (otherwise contains type declarations) +PT_SILENT = 0x0002 # silent mode +PT_PAKDEF = 0x0000 # default pack value +PT_PAK1 = 0x0010 # #pragma pack(1) +PT_PAK2 = 0x0020 # #pragma pack(2) +PT_PAK4 = 0x0030 # #pragma pack(4) +PT_PAK8 = 0x0040 # #pragma pack(8) +PT_PAK16 = 0x0050 # #pragma pack(16) + +# ---------------------------------------------------------------------------- +# H I D D E N A R E A S +# ---------------------------------------------------------------------------- +def HideArea(start, end, description, header, footer, color): + """ + Hide an area + + Hidden areas - address ranges which can be replaced by their descriptions + + @param start: area start + @param end: area end + @param description: description to display if the area is collapsed + @param header: header lines to display if the area is expanded + @param footer: footer lines to display if the area is expanded + @param color: RGB color code (-1 means default color) + + @returns: !=0 - ok + """ + return idaapi.add_hidden_area(start, end, description, header, footer, color) + + +def SetHiddenArea(ea, visible): + """ + Set hidden area state + + @param ea: any address belonging to the hidden area + @param visible: new state of the area + + @return: != 0 - ok + """ + ha = idaapi.get_hidden_area(ea) + + if not ha: + return 0 + else: + ha.visible = visible + return idaapi.update_hidden_area(ha) + + +def DelHiddenArea(ea): + """ + Delete a hidden area + + @param ea: any address belonging to the hidden area + @returns: != 0 - ok + """ + return idaapi.del_hidden_area(ea) + + +#-------------------------------------------------------------------------- +# D E B U G G E R I N T E R F A C E +#-------------------------------------------------------------------------- + +def GetRegValue(name): + """ + Get register value + + @param name: the register name + + @note: The debugger should be running. otherwise the function fails + the register name should be valid. + It is not necessary to use this function to get register values + because a register name in the script will do too. + + @return: register value (integer or floating point) + """ + rv = idaapi.regval_t() + res = idaapi.get_reg_val(name, rv) + assert res, "get_reg_val() failed, bogus name perhaps?" + return rv.ival + + +def SetRegValue(value, name): + """ + Set register value + + @param name: the register name + @param value: new register value + + @note: The debugger should be running + It is not necessary to use this function to set register values. + A register name in the left side of an assignment will do too. + """ + rv = idaapi.regval_t() + rv.ival = value + return idaapi.set_reg_val(name, value) + + +def GetBptQty(): + """ + Get number of breakpoints. + + @return: number of breakpoints + """ + return idaapi.get_bpt_qty() + + +def GetBptEA(n): + """ + Get breakpoint address + + @param n: number of breakpoint, is in range 0..GetBptQty()-1 + + @return: addresss of the breakpoint or BADADDR + """ + bpt = idaapi.bpt_t() + + if idaapi.getn_bpt(n, bpt): + return bpt.ea + else: + return BADADDR + + +def GetBptAttr(ea, bptattr): + """ + Get the characteristics of a breakpoint + + @param address: any address in the breakpoint range + @param bptattr: the desired attribute code, one of BPTATTR_... constants + + @return: the desired attribute value or -1 + """ + bpt = idaapi.bpt_t() + + if not idaapi.get_bpt(ea, bpt): + return -1 + else: + if bptattr == BPTATTR_EA: + return bpt.ea + if bptattr == BPTATTR_SIZE: + return bpt.size + if bptattr == BPTATTR_TYPE: + return bpt.type + if bptattr == BPTATTR_COUNT: + return bpt.pass_count + if bptattr == BPTATTR_FLAGS: + return bpt.flags + if bptattr == BPTATTR_COND: + return bpt.condition + return -1 + + +BPTATTR_EA = 0 # starting address of the breakpoint +BPTATTR_SIZE = 4 # size of the breakpoint (undefined if software breakpoint) +BPTATTR_TYPE = 8 # type of the breakpoint +BPTATTR_COUNT = 12 # how many times does the execution reach this breakpoint ? +BPTATTR_FLAGS = 16 # Breakpoint attributes: +BPTATTR_COND = 20 # Breakpoint condition NOTE: the return value is a string in this case + +# Breakpoint types: +BPT_EXEC = 0 # Hardware: Execute instruction +BPT_WRITE = 1 # Hardware: Write access +BPT_RDWR = 3 # Hardware: Read/write access +BPT_SOFT = 4 # Software breakpoint + +BPT_BRK = 0x01 # does the debugger stop on this breakpoint? +BPT_TRACE = 0x02 # does the debugger add trace information when this breakpoint is reached? + + +def SetBptAttr(address, bptattr, value): + """ + modifiable characteristics of a breakpoint + + @param address: any address in the breakpoint range + @param bptattr: the attribute code, one of BPTATTR_* constants + BPTATTR_CND is not allowed, see SetBptCnd() + @param value: the attibute value + + @return: success + """ + bpt = idaapi.bpt_t() + + if not idaapi.get_bpt(address, bpt): + return False + else: + if bptattr not in [ BPTATTR_SIZE, BPTATTR_TYPE, BPTATTR_FLAGS, BPTATTR_COUNT ]: + return False + if bptattr == BPTATTR_SIZE: + bpt.size = value + if bptattr == BPTATTR_TYPE: + bpt.type = value + if bptattr == BPTATTR_COUNT: + bpt.pass_count = value + if bptattr == BPTATTR_FLAGS: + bpt.flags = value + + idaapi.update_bpt(bpt) + return True + + +def SetBptCnd(ea, cnd): + """ + Set breakpoint condition + + @param address: any address in the breakpoint range + @param cnd: breakpoint condition + + @return: success + FIXME: unimplemented + """ + raise NotImplementedError + + +def AddBptEx(ea, size, bpttype): + """ + Add a new breakpoint + + @param ea: any address in the process memory space: + @param size: size of the breakpoint (irrelevant for software breakpoints): + @param type: type of the breakpoint (one of BPT_... constants) + + @return: success + + @note: Only one breakpoint can exist at a given address. + """ + return idaapi.add_bpt(ea, size, bpttype) + + +def AddBpt(ea): return AddBptEx(ea, 0, BPT_SOFT) + + +def DelBpt(ea): + """ + Delete breakpoint + + @param ea: any address in the process memory space: + + @return: success + """ + return idaapi.del_bpt(ea) + + +def EnableBpt(ea, enable): + """ + Enable/disable breakpoint + + @param ea: any address in the process memory space: + + @return: success + + @note: Disabled breakpoints are not written to the process memory + """ + return idaapi.enable_bpt(ea, enable) + + +#-------------------------------------------------------------------------- +# C O L O R S +#-------------------------------------------------------------------------- + +def GetColor(ea, what): + """ + Get item color + + @param ea: address of the item + @param what: type of the item (one of CIC_* constants) + + @return: color code in RGB (hex 0xBBGGRR) + """ + if what not in [ CIC_ITEM, CIC_FUNC, CIC_SEGM ]: + raise ValueError, "'what' must be one of CIC_ITEM, CIC_FUNC and CIC_SEGM" + + if what == CIC_ITEM: + return idaapi.get_item_color(ea) + + if what == CIC_FUNC: + func = idaapi.get_func(ea) + if func: + return func.color + else: + return DEFCOLOR + + if what == CIC_SEGM: + seg = idaapi.getseg(ea) + if seg: + return seg.color + else: + return DEFCOLOR + +# color item codes: +CIC_ITEM = 1 # one instruction or data +CIC_FUNC = 2 # function +CIC_SEGM = 3 # segment + +DEFCOLOR = 0xFFFFFFFF # Default color + + +def SetColor(ea, what, color): + """ + Set item color + + @param ea: address of the item + @param what: type of the item (one of CIC_* constants) + @param color: new color code in RGB (hex 0xBBGGRR) + + @return: success (True or False) + """ + if what not in [ CIC_ITEM, CIC_FUNC, CIC_SEGM ]: + raise ValueError, "'what' must be one of CIC_ITEM, CIC_FUNC and CIC_SEGM" + + if what == CIC_ITEM: + return idaapi.set_item_color(ea, color) + + if what == CIC_FUNC: + func = idaapi.get_func(ea) + if func: + func.color = color + return True + else: + return False + + if what == CIC_SEGM: + seg = idaapi.getseg(ea) + if seg: + seg.color = color + return True + else: + return False + + + +#-------------------------------------------------------------------------- +# X M L +#-------------------------------------------------------------------------- + +def SetXML(path, name, value): + """ + Set or update one or more XML values. + + @param path: XPath expression of elements where to create value(s) + @param name: name of the element/attribute + (use @XXX for an attribute) to create. + If 'name' is empty, the elements or + attributes returned by XPath are directly + updated to contain the new 'value'. + @param value: value of the element/attribute + + @return: success (True or False) + """ + return idaapi.set_xml(path, name, value) + + +def GetXML(path): + """ + Get one XML value. + + @param path: XPath expression to an element + or attribute whose value is requested + + @return: the value, None if failed + """ + v = idaapi.value_t() + if idaapi.get_xml(path): + return v.str + else: + return None + + +#-------------------------------------------------------------------------- +# Compatibility macros: +def OpOffset(ea,base): return OpOff(ea,-1,base) +def OpNum(ea): return OpNumber(ea,-1) +def OpChar(ea): return OpChr(ea,-1) +def OpSegment(ea): return OpSeg(ea,-1) +def OpDec(ea): return OpDecimal(ea,-1) +def OpAlt1(ea,str): return OpAlt(ea,0,str) +def OpAlt2(ea,str): return OpAlt(ea,1,str) +def StringStp(x): return SetCharPrm(INF_ASCII_BREAK,x) +def LowVoids(x): return SetLongPrm(INF_LOW_OFF,x) +def HighVoids(x): return SetLongPrm(INF_HIGH_OFF,x) +def TailDepth(x): return SetLongPrm(INF_MAXREF,x) +def Analysis(x): return SetCharPrm(INF_AUTO,x) +def Tabs(x): return SetCharPrm(INF_ENTAB,x) +#def Comments(x): SetCharPrm(INF_CMTFLAG,((x) ? (SW_ALLCMT|GetCharPrm(INF_CMTFLAG)) : (~SW_ALLCMT&GetCharPrm(INF_CMTFLAG)))) +def Voids(x): return SetCharPrm(INF_VOIDS,x) +def XrefShow(x): return SetCharPrm(INF_XREFNUM,x) +def Indent(x): return SetCharPrm(INF_INDENT,x) +def CmtIndent(x): return SetCharPrm(INF_COMMENT,x) +def AutoShow(x): return SetCharPrm(INF_SHOWAUTO,x) +def MinEA(): return GetLongPrm(INF_MIN_EA) +def MaxEA(): return GetLongPrm(INF_MAX_EA) +def BeginEA(): return GetLongPrm(INF_BEGIN_EA) +def set_start_cs(x): return SetLongPrm(INF_START_CS,x) +def set_start_ip(x): return SetLongPrm(INF_START_IP,x) + +def WriteMap(filepath): + return GenerateFile(OFILE_MAP, filepath, 0, BADADDR, GENFLG_MAPSEGS|GENFLG_MAPNAME) + +def WriteTxt(filepath, ea1, ea2): + return GenerateFile(OFILE_ASM, filepath, ea1, ea2, 0) + +def WriteExe(filepath): + return GenerateFile(OFILE_EXE, filepath, 0, BADADDR, 0) + +def AddConst(enum_id,name,value): return AddConstEx(enum_id,name,value,-1) +def AddStruc(index,name): return AddStrucEx(index,name,0) +def AddUnion(index,name): return AddStrucEx(index,name,1) +#def OpStroff(ea,n,strid): OpStroffEx(ea,n,strid,0) +def OpEnum(ea,n,enumid): return OpEnumEx(ea,n,enumid,0) +def DelConst(id,v,mask): return DelConstEx(id,v,0,mask) +def GetConst(id,v,mask): return GetConstEx(id,v,0,mask) +def AnalyseArea(sEA, eEA): AnalyzeArea(sEA,eEA) + +def MakeStruct(ea,name): return MakeStructEx(ea, -1, name) +def Name(ea): return NameEx(BADADDR, ea) +def GetTrueName(ea): return GetTrueNameEx(BADADDR, ea) +def MakeName(ea, name): MakeNameEx(ea,name,SN_CHECK) + +def GetFrame(ea): return GetFunctionAttr(ea, FUNCATTR_FRAME) +def GetFrameLvarSize(ea): return GetFunctionAttr(ea, FUNCATTR_FRSIZE) +def GetFrameRegsSize(ea): return GetFunctionAttr(ea, FUNCATTR_FRREGS) +def GetFrameArgsSize(ea): return GetFunctionAttr(ea, FUNCATTR_ARGSIZE) +def GetFunctionFlags(ea): return GetFunctionAttr(ea, FUNCATTR_FLAGS) +def SetFunctionFlags(ea, flags): return SetFunctionAttr(ea, FUNCATTR_FLAGS, flags) + +def SegStart(ea): return GetSegmentAttr(ea, SEGATTR_START) +def SegEnd(ea): return GetSegmentAttr(ea, SEGATTR_END) +def SetSegmentType(ea, type): return SetSegmentAttr(ea, SEGATTR_TYPE, type) + +def Comment(ea): return GetCommentEx(ea, 0) +def RptCmt(ea): return GetCommentEx(ea, 1) + +def loadfile(filepath, pos, ea, size): return LoadFile(filepath, pos, ea, size) +def savefile(filepath, pos, ea, size): return SaveFile(filepath, pos, ea, size) + +# A convenice macro: +def here(): return ScreenEA() + +# END OF IDC COMPATIBILY CODE diff --git a/python/init.py b/python/init.py new file mode 100644 index 0000000..9a05a18 --- /dev/null +++ b/python/init.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python +#------------------------------------------------------------ +# IDAPython - Python plugin for Interactive Disassembler Pro +# +# Copyright (c) 2004-2007 Gergely Erdelyi +# +# All rights reserved. +# +# For detailed copyright information see the file COPYING in +# the root of the distribution archive. +#------------------------------------------------------------ +# init.py - Essential init routines +#------------------------------------------------------------ +import sys, os, os.path, traceback, warnings +import _idaapi + +# FIXME: Should fix the offending constant instead +warnings.filterwarnings('ignore', category=FutureWarning) + + +def addscriptpath(script): + """ + Add the path part of the scriptfile to the system path to + allow modules to be loaded from the same place. + + Each path is added only once. + """ + pathfound = 0 + + scriptpath = os.path.dirname(script) + + for pathitem in sys.path: + if pathitem == scriptpath: + pathfound = 1 + break + + if pathfound == 0: + sys.path.append(scriptpath) + + # Add the script to ScriptBox if it's not there yet + if not script in ScriptBox_instance.list: + ScriptBox_instance.list.insert(0, script) + + +def runscript(script): + """ + Run the specified script after adding its directory path to + system path. + + This function is used by the low-level plugin code. + """ + addscriptpath(script) + argv = sys.argv + sys.argv = [ script ] + execfile(script, globals()) + sys.argv = argv + +def print_banner(): + version1 = "IDAPython version %d.%d.%d %s (serial %d) initialized" % IDAPYTHON_VERSION + version2 = "Python interpreter version %d.%d.%d %s (serial %d)" % sys.version_info + linelen = max(len(version1), len(version2)) + + print '-' * linelen + print version1 + print version2 + print '-' * linelen + + +#----------------------------------------------------------- +# Take over the standard text outputs +#----------------------------------------------------------- +class MyStdOut: + """ + Dummy file-like class that receives stout and stderr + """ + def write(self, text): + _idaapi.msg(text.replace("%", "%%")) + + def flush(self): + pass + + +# Redirect stderr and stdout to the IDA message window +sys.stdout = sys.stderr = MyStdOut() + +# Assign a default sys.argv +sys.argv = [ "" ] + +# Have to make sure Python finds our modules +sys.path.append(_idaapi.idadir("python")) + +print_banner() + +#----------------------------------------------------------- +# Import all the required modules +#----------------------------------------------------------- +from idc import * +from idautils import * + + +#----------------------------------------------------------- +# Build up the ScriptBox tool +#----------------------------------------------------------- +class ScriptBox(Choose): + def __init__(self, list=[]): + Choose.__init__(self, list, "ScriptBox", 1) + self.width = 50 + + def run(self): + if len(self.list) == 0: + Warning("ScriptBox history is empty.\nRun some script with Alt-9 and try again.") + return None + + n = self.choose() + + if n > 0: + return self.list[n-1] + else: + return None + + def addscript(self, scriptpath): + self.list.append(scriptpath) + +ScriptBox_instance = ScriptBox([]) + +# Load the users personal init file +userrc = get_user_idadir() + os.sep + "idapythonrc.py" + +if os.path.exists(userrc): + runscript(userrc) + # Remove the user script from the history + del ScriptBox_instance.list[0] + + +# All done, ready to rock. diff --git a/swig/auto.i b/swig/auto.i new file mode 100644 index 0000000..8169599 --- /dev/null +++ b/swig/auto.i @@ -0,0 +1,13 @@ +%ignore auto_process_all; +%ignore autoPlanned; +%ignore nextPlanned; +%ignore autoDelCode; +%ignore autoPeek; +%ignore autoProcess; +%ignore auto_init; +%ignore auto_save; +%ignore auto_term; +%ignore ea_without_xrefs; + +%include "auto.hpp" + diff --git a/swig/bytes.i b/swig/bytes.i new file mode 100644 index 0000000..a5f5b58 --- /dev/null +++ b/swig/bytes.i @@ -0,0 +1,72 @@ +// This makes put_many_bytes and patch_many_bytes work nicely +%apply (char *STRING, int LENGTH) { (const void *buf, size_t size) }; + +// Make get_any_cmt() work +%apply unsigned char *OUTPUT { color_t *cmttype }; + +// For get_enum_id() +%apply unsigned char *OUTPUT { uchar *serial }; + +// Unexported and kernel-only declarations +%ignore FlagsEnable; +%ignore FlagsDisable; +%ignore testf_t; +%ignore nextthat; +%ignore prevthat; +%ignore adjust_visea; +%ignore prev_visea; +%ignore next_visea; +%ignore is_first_visea; +%ignore is_last_visea; +%ignore is_visible_finally; +%ignore invalidate_visea_cache; +%ignore fluFlags; +%ignore setFlbits; +%ignore clrFlbits; +%ignore get_8bit; +%ignore get_ascii_char; +%ignore del_typeinfo; +%ignore del_operand_typeinfo; +%ignore doCode; +%ignore get_repeatable_cmt; +%ignore get_any_indented_cmt; +%ignore del_code_comments; +%ignore doFlow; +%ignore noFlow; +%ignore doRef; +%ignore noRef; +%ignore doExtra; +%ignore noExtra; +%ignore coagulate; +%ignore coagulate_dref; +%ignore get_item_head; +%ignore init_hidden_areas; +%ignore save_hidden_areas; +%ignore term_hidden_areas; +%ignore check_move_args; +%ignore movechunk; +%ignore lock_dbgmem_config; +%ignore unlock_dbgmem_config; +%ignore set_op_type_no_event; +%ignore ida_vpagesize; +%ignore ida_vpages; +%ignore ida_npagesize; +%ignore ida_npages; +%ignore FlagsInit; +%ignore FlagsTerm; +%ignore FlagsReset; + +// TODO: These could be fixed if someone needs them. +%ignore get_many_bytes; +%ignore put_many_bytes; +%ignore patch_many_bytes; +%ignore set_dbgmem_source; +%ignore invalidate_dbgmem_config; +%ignore invalidate_dbgmem_contents; +%ignore is_debugger_on; + +%include "bytes.hpp" + +%clear(const void *buf, size_t size); +%clear(void *buf, ssize_t size); +%clear(typeinfo_t *); diff --git a/swig/dbg.i b/swig/dbg.i new file mode 100644 index 0000000..d89574b --- /dev/null +++ b/swig/dbg.i @@ -0,0 +1,10 @@ +// SWIG chokes on the original declaration so it is replicated here +typedef struct +{ + ulonglong ival; // 8: integer value + ushort fval[6]; // 12: floating point value in the internal representation (see ieee.h) +} regval_t; + +%immutable dbg; +%include "dbg.hpp" + diff --git a/swig/diskio.i b/swig/diskio.i new file mode 100644 index 0000000..c2857ad --- /dev/null +++ b/swig/diskio.i @@ -0,0 +1,43 @@ +// TODO: These could be wrapped +%ignore enumerate_files; +%ignore enumerate_system_files; +%ignore ioport_bit_t; +%ignore ioport_bits_t; +%ignore ioport_t; +%ignore read_ioports; +%ignore choose_ioport_device; +%ignore find_ioport; +%ignore find_ioport_bit; +%ignore free_ioports; +%ignore lread; +%ignore qlread; +%ignore qlgets; +%ignore qlgetc; +%ignore lreadbytes; +%ignore lread2bytes; +%ignore lread2bytes; +%ignore lread4bytes; +%ignore lread4bytes; +%ignore lread8bytes; +%ignore lread8bytes; +%ignore qlsize; +%ignore qlseek; +%ignore qltell; +%ignore qlfile; +%ignore make_linput; +%ignore unmake_linput; + +// FIXME: These should be wrapped for completeness +%ignore eread; +%ignore ewrite; + +// Ignore kernel-only & unexported symbols +%ignore get_thread_priority; +%ignore set_thread_priority; +%ignore checkdspace; +%ignore lowdiskgo; +%ignore ida_argv; +%ignore exename; + +%include "diskio.hpp" + diff --git a/swig/entry.i b/swig/entry.i new file mode 100644 index 0000000..4fb1cf9 --- /dev/null +++ b/swig/entry.i @@ -0,0 +1,7 @@ +%ignore init_entries; +%ignore term_entries; +%ignore move_entries; +%ignore set_entry_name; + +%include "entry.hpp" + diff --git a/swig/enum.i b/swig/enum.i new file mode 100644 index 0000000..2227dfc --- /dev/null +++ b/swig/enum.i @@ -0,0 +1,28 @@ +// Kernel only & unexported symbols +%ignore enums; +%ignore init_enums; +%ignore save_enums; +%ignore term_enums; +%ignore get_selected_enum; +%ignore add_selected_enum; +%ignore unmark_selected_enums; +%ignore is_good_bmask; +%ignore get_bmask_enum; +%ignore ENUM_REVERSE; +%ignore ENUM_SELMEMS; +%ignore ENUM_QTY_IDX; +%ignore ENUM_FLG_IDX; +%ignore ENUM_FLAGS; +%ignore ENUM_FLAGS_IS_BF; +%ignore ENUM_FLAGS_HIDDEN; +%ignore ENUM_MASKS; +%ignore ENUM_MEMBERS; +%ignore CONST_ENUM; +%ignore CONST_VALUE; +%ignore CONST_BMASK; +%ignore CONST_SERIAL; +%ignore CONST_SERIALS; + +// FIXME: Check uval_t declarations + +%include "enum.hpp" diff --git a/swig/expr.i b/swig/expr.i new file mode 100644 index 0000000..597362f --- /dev/null +++ b/swig/expr.i @@ -0,0 +1,32 @@ +%ignore extfun_t; +%ignore funcset_t; +%ignore IDCFuncs; +%ignore set_idc_func; +%ignore VarLong; +%ignore VarNum; +%ignore VarString; +%ignore VarFloat; +%ignore VarFree; +%ignore calcexpr_long; +%ignore CompileEx; +%ignore Compile; +%ignore CompileLine; +%ignore Run; +%ignore ExecuteLine; +%ignore ExecuteFile; +%ignore set_idc_func_body; +%ignore get_idc_func_body; +%ignore idc_stacksize; +%ignore idc_calldepth; +%ignore expr_printf; +%ignore expr_sprintf; +%ignore expr_printfer; +%ignore idaapi init_idc; +%ignore idaapi term_idc; +%ignore del_idc_userfuncs; +%ignore find_builtin_idc_func; +%ignore idc_lx; + +%include "expr.hpp" + + diff --git a/swig/fixup.i b/swig/fixup.i new file mode 100644 index 0000000..d900cb3 --- /dev/null +++ b/swig/fixup.i @@ -0,0 +1,6 @@ +%ignore apply_fixup; +%ignore convert_fixups; +%ignore move_fixups; + +%include "fixup.hpp" + diff --git a/swig/frame.i b/swig/frame.i new file mode 100644 index 0000000..c5e7503 --- /dev/null +++ b/swig/frame.i @@ -0,0 +1,20 @@ +%ignore add_frame_spec_member; +%ignore del_stkvars; +%ignore calc_frame_offset; +%ignore read_regvars; +%ignore write_regvars; +%ignore del_regvars; +%ignore free_regvar; +%ignore gen_regvar_defs; +%ignore set_llabel; +%ignore get_llabel_ea; +%ignore get_llabel; +%ignore read_llabels; +%ignore write_llabels; +%ignore del_llabels; +%ignore free_llabel; +%ignore read_stkpnts; +%ignore write_stkpnts; +%ignore del_stkpnts; + +%include "frame.hpp" diff --git a/swig/funcs.i b/swig/funcs.i new file mode 100644 index 0000000..863f47b --- /dev/null +++ b/swig/funcs.i @@ -0,0 +1,36 @@ +%cstring_bounded_output_none(char *buf, MAXSTR); +%cstring_bounded_output_none(char *optlibs, MAXSTR); + +// FIXME: These should probably be fixed +%ignore iterate_func_chunks; +%ignore get_idasgn_desc; +%ignore get_sig_filename; +%ignore get_idasgn_header_by_short_name; +%ignore get_idasgn_title; + +// Kernel-only & unexported symbols +%ignore del_regargs; +%ignore write_regargs; +%ignore find_regarg; +%ignore free_regarg; +%ignore determine_rtl; +%ignore init_signatures; +%ignore save_signatures; +%ignore term_signatures; +%ignore init_funcs; +%ignore save_funcs; +%ignore term_funcs; +%ignore move_funcs; +%ignore copy_noret_info; +%ignore recalc_func_noret_flag; +%ignore plan_for_noret_analysis; +%ignore invalidate_sp_analysis; + +%ignore create_func_eas_array; +%ignore auto_add_func_tails; + +%include "funcs.hpp" + +%clear(char *buf); +%clear(char *optlibs); + diff --git a/swig/ida.i b/swig/ida.i new file mode 100644 index 0000000..abfe486 --- /dev/null +++ b/swig/ida.i @@ -0,0 +1,13 @@ +// Ignore kernel-only symbols +%ignore dual_text_options_t; +%ignore init; +%ignore retrieve; +%ignore read; +%ignore write; + +// Make idainfo::get_proc_name() work +%cstring_bounded_output(char *buf, 8); + +%include "ida.hpp" + +%clear(char *buf); diff --git a/swig/idaapi.i b/swig/idaapi.i new file mode 100644 index 0000000..76cef32 --- /dev/null +++ b/swig/idaapi.i @@ -0,0 +1,112 @@ +%module(docstring="IDA Pro Plugin SDK API wrapper") idaapi +// Suppress 'previous definition of XX' warnings +#pragma SWIG nowarn=302 +// Enable automatic docstring generation +%feature(autodoc); +%{ +#include +#define USE_DANGEROUS_FUNCTIONS 1 +#ifdef HAVE_SSIZE_T +#define _SSIZE_T_DEFINED 1 +#endif +#include "ida.hpp" +#include "auto.hpp" +#include "bytes.hpp" +#include "dbg.hpp" +#include "diskio.hpp" +#include "entry.hpp" +#include "enum.hpp" +#include "expr.hpp" +#include "frame.hpp" +#include "fixup.hpp" +#include "funcs.hpp" +#include "idd.hpp" +#include "idp.hpp" +#include "ints.hpp" +#include "kernwin.hpp" +#include "lines.hpp" +#include "loader.hpp" +#include "moves.hpp" +#include "nalt.hpp" +#include "name.hpp" +#include "offset.hpp" +#include "queue.hpp" +#include "search.hpp" +#include "srarea.hpp" +#include "strlist.hpp" +#include "struct.hpp" +#include "typeinf.hpp" +#include "ua.hpp" +#include "xref.hpp" +%} + +%constant ea_t BADADDR = 0xFFFFFFFF; +%constant sel_t BADSEL = 0xFFFFFFFF; + +// Help SWIG to figure out the ulonglong type +#ifdef SWIGWIN +typedef unsigned __int64 ulonglong; +typedef __int64 longlong; +#else +typedef unsigned long long ulonglong; +typedef long long longlong; +#endif + +%include "typemaps.i" + +%include "cstring.i" +%include "carrays.i" +%include "cpointer.i" + +%include "typeconv.i" + +%include "pro.h" + +// Convert all of these +%cstring_output_maxstr_none(char *buf, size_t bufsize); + +%array_class(uchar, ucharArray); +%array_class(tid_t, tidArray); +%pointer_class(int, int_pointer); + +%include "ida.i" +%include "idd.hpp" +%include "idp.i" + +%include "area.hpp" +%include "auto.i" +%include "bytes.i" +%include "dbg.i" +%include "diskio.i" +%include "entry.i" +%include "enum.i" +%include "expr.i" +%include "fixup.i" +%include "frame.i" +%include "funcs.i" + +%inline { +/* Small wrapper to get the inf structure */ +idainfo *get_inf_structure(void) +{ + return &inf; +} +} + +%include "ints.i" +%include "kernwin.i" +%include "lines.i" +%include "loader.i" +%include "moves.i" +%include "nalt.i" +%include "name.i" +%include "offset.i" +%include "queue.i" +%include "search.i" +%include "segment.i" +%include "srarea.i" +%include "strlist.i" +%include "struct.i" +%include "typeinf.i" +%include "ua.i" +%include "xref.i" diff --git a/swig/idp.i b/swig/idp.i new file mode 100644 index 0000000..0ca4590 --- /dev/null +++ b/swig/idp.i @@ -0,0 +1,3 @@ +%ignore gen_idb_event; + +%include "idp.hpp" diff --git a/swig/ints.i b/swig/ints.i new file mode 100644 index 0000000..5a57a31 --- /dev/null +++ b/swig/ints.i @@ -0,0 +1,6 @@ +// Kernel-only symbols +%ignore init_predefs; +%ignore term_predefs; + +%include "ints.i" + diff --git a/swig/kernwin.i b/swig/kernwin.i new file mode 100644 index 0000000..b4bef83 --- /dev/null +++ b/swig/kernwin.i @@ -0,0 +1,217 @@ +%include "typemaps.i" + +// Make askaddr(), askseg(), and asklong() return a +// tuple: (result, value) +%apply unsigned long *INOUT { sval_t *value }; +%rename (_asklong) asklong; +%apply unsigned long *INOUT { ea_t *addr }; +%rename (_askaddr) askaddr; +%apply unsigned long *INOUT { sel_t *sel }; +%rename (_askseg) askseg; + +%pythoncode %{ +def asklong(defval, format): + res, val = _idaapi._asklong(defval, format) + + if res == 1: + return val + else: + return None + +def askaddr(defval, format): + res, ea = _idaapi._askaddr(defval, format) + + if res == 1: + return ea + else: + return None + +def askseg(defval, format): + res, sel = _idaapi._askseg(defval, format) + + if res == 1: + return sel + else: + return None + +%} + +# This is for get_cursor() +%apply int *OUTPUT {int *x, int *y}; + +# This is for read_selection() +%apply unsigned long *OUTPUT { ea_t *ea1, ea_t *ea2 }; + +// Ignore the va_list functions +%ignore AskUsingForm_cv; +%ignore close_form; +%ignore vaskstr; +%ignore vasktext; +%ignore vwarning; +%ignore vinfo; +%ignore vnomem; +%ignore vmsg; +%ignore show_wait_box_v; +%ignore askbuttons_cv; +%ignore askfile_cv; +%ignore askyn_cv; +%ignore askyn_v; +// Ignore these string functions. There are trivial replacements in Python. +%ignore addblanks; +%ignore trim; +%ignore skipSpaces; +%ignore stristr; + + +%include "kernwin.hpp" + +ulong choose_choose(PyObject *self, + int flags, + int x0,int y0, + int x1,int y1, + int width); + +%{ +ulong idaapi choose_sizer(void *self) +{ + PyObject *pyres; + ulong res; + + pyres = PyObject_CallMethod((PyObject *)self, "sizer", ""); + res = PyInt_AsLong(pyres); + Py_DECREF(pyres); + return res; +} + +char * idaapi choose_getl(void *self, ulong n, char *buf) +{ + PyObject *pyres; + char *res; + + char tmp[1024]; + + pyres = PyObject_CallMethod((PyObject *)self, "getl", "l", n); + + if (!pyres) + { + strcpy(buf, ""); + return buf; + } + + res = PyString_AsString(pyres); + + if (res) + { + strcpy(buf, res); + res = buf; + } + else + { + strcpy(buf, ""); + res = buf; + } + + Py_DECREF(pyres); + return res; +} + +void idaapi choose_enter(void *self, ulong n) +{ + PyObject_CallMethod((PyObject *)self, "enter", "l", n); + return; +} + +ulong choose_choose(void *self, + int flags, + int x0,int y0, + int x1,int y1, + int width) +{ + PyObject *pytitle; + + char deftitle[] = "Choose"; + char *title = NULL; + + if ((pytitle = PyObject_GetAttrString((PyObject *)self, "title"))) + { + title = PyString_AsString(pytitle); + } + + return choose( + flags, // various flags: see above for description + x0, y0, // x0=-1 for autoposition + x1, y1, + self, // object to show + width, // Max width of lines + &choose_sizer, // Number of items + &choose_getl, // Description of n-th item (1..n) + // 0-th item if header line + title ? title : deftitle, + 1, + 1, + NULL, + NULL, + NULL, + NULL, + &choose_enter + ); // number of the default icon to display +} +%} + +%pythoncode %{ +class Choose: + """ + Choose - class for choose() with callbacks + """ + def __init__(self, list, title, flags=0): + self.list = list + self.title = title + + self.flags = flags + self.x0 = -1 + self.x1 = -1 + self.y0 = -1 + self.y1 = -1 + + self.width = -1 + + def sizer(self): + """ + Callback: sizer - returns the length of the list + """ + return len(self.list) + + def getl(self, n): + """ + Callback: getl - get one item from the list + """ + if n <= len(self.list): + return self.list[n-1] + else: + return "" + + def ins(self): + pass + + def update(self, n): + pass + + def edit(self, n): + pass + + def enter(self, n): + print "enter(%d) called" % n + + def destroy(self): + pass + + def get_icon(self, n): + pass + + def choose(self): + """ + choose - Display the choose dialogue + """ + return _idaapi.choose_choose(self, self.flags, self.x0, self.y0, self.x1, self.y1, self.width) +%} + diff --git a/swig/lines.i b/swig/lines.i new file mode 100644 index 0000000..6643f82 --- /dev/null +++ b/swig/lines.i @@ -0,0 +1,63 @@ +// Convert this for ver 4.8 tag_remove() +%cstring_output_maxstr_none(char *buf, int bufsize); + +// FIXME: These should be fixed +%ignore tag_on; +%ignore tag_off; +%ignore tag_addchr; +%ignore tag_addstr; +%ignore tag_addr; +%ignore tag_advance; +%ignore tag_skipcodes; +%ignore tag_skipcode; +%ignore set_user_defined_prefix; +%ignore get_user_defined_prefix; +// Ignore va_list versions +%ignore printf_line_v; +%ignore gen_colored_cmt_line_v; +%ignore gen_cmt_line_v; +%ignore add_long_cmt_v; +%ignore describex; +// Kernel-only and unexported symbols +%ignore init_sourcefiles; +%ignore save_sourcefiles; +%ignore term_sourcefiles; +%ignore move_sourcefiles; +%ignore gen_xref_lines; +%ignore ml_getcmt_t; +%ignore ml_getnam_t; +%ignore ml_genxrf_t; +%ignore ml_saver_t; +%ignore setup_makeline; +%ignore MAKELINE_NONE; +%ignore MAKELINE_BINPREF; +%ignore MAKELINE_VOID; +%ignore MAKELINE_STACK; +%ignore save_line_in_array; +%ignore init_lines_array; +%ignore finish_makeline; +%ignore generate_disassembly; +%ignore gen_labeled_line; +%ignore gen_lname_line; +%ignore makeline_producer_t; +%ignore set_makeline_producer; +%ignore closing_comment; +%ignore close_comment; +%ignore copy_extra_lines; +%ignore ExtraLines; +%ignore ExtraKill; +%ignore ExtraFree; +%ignore Dumper; +%ignore init_lines; +%ignore save_lines; +%ignore term_lines; +%ignore gl_namedone; +%ignore data_as_stack; +%ignore calc_stack_alignment; +%ignore align_down_to_stack; +%ignore align_up_to_stack; +%ignore remove_spaces; + +%include "lines.hpp" + +%clear(char *buf, int bufsize); diff --git a/swig/loader.i b/swig/loader.i new file mode 100644 index 0000000..cb0a96f --- /dev/null +++ b/swig/loader.i @@ -0,0 +1,123 @@ +// Ignore callback members +%ignore loader_t::accept_file; +%ignore loader_t::load_file; +%ignore loader_t::save_file; +%ignore loader_t::move_segm; +%ignore loader_t::init_loader_options; +%ignore plugin_t::init; +%ignore plugin_t::term; +%ignore plugin_t::run; + +%ignore vloader_failure; +%ignore loader_failure; + +// TODO: These could be wrapped if needed +%ignore load_info_t; +%ignore build_loaders_list; +%ignore free_loaders_list; +%ignore get_loader_name_from_dll; +%ignore get_loader_name; +%ignore init_loader_options; +%ignore load_nonbinary_file; +%ignore impinfo_t; +%ignore import_module; +%ignore plugin_info_t; +%ignore get_plugins; +%ignore invoke_plugin; +%ignore dbg_info_t; +%ignore get_debugger_plugins; +%ignore init_plugins; +%ignore term_plugins; + +// Callback and loader-only symbols are ignored (for now) +%ignore html_header_cb_t; +%ignore html_footer_cb_t; +%ignore html_line_cb_t; +%ignore gen_outline_t; +%ignore create_filename_cmt; +%ignore hook_cb_t; +%ignore hook_type_t; +%ignore hook_to_notification_point; +%ignore unhook_from_notification_point; +%ignore invoke_callbacks; + +// Ignore kernel-only & unexported symbols +%ignore LDSC; +%ignore PLUGIN; +%ignore LNE_MAXSEG; +%ignore dlldata; +%ignore DLLDATASTART; +%ignore ldrdata; +%ignore LDRDATASTART; +%ignore idadll_t; +%ignore load_dll; +%ignore RE_NOFILE; +%ignore RE_NOTIDP; +%ignore RE_NOPAGE; +%ignore RE_NOLINK; +%ignore RE_BADRTP; +%ignore RE_BADORD; +%ignore RE_BADATP; +%ignore RE_BADMAP; +%ignore load_dll_or_die; +%ignore load_dll_or_say; +%ignore free_dll; +%ignore IDP_DESC_START; +%ignore IDP_DESC_END; +%ignore get_idp_desc; +%ignore init_fileregions; +%ignore term_fileregions; +%ignore save_fileregions; +%ignore add_fileregion; +%ignore move_fileregions; +%ignore local_gen_idc_file; +%ignore print_all_places; +%ignore save_text_line; +%ignore print_all_structs; +%ignore print_all_enums; +%ignore database_id0; +%ignore is_database_ext; +%ignore ida_database_memory; +%ignore database_flags; +%ignore DBFL_KILL; +%ignore DBFL_COMP; +%ignore DBFL_BAK; +%ignore DBFL_TEMP; +%ignore is_temp_database; +%ignore pe_create_idata; +%ignore pe_load_resources; +%ignore pe_create_flat_group; +%ignore dbcheck_t; +%ignore DBCHK_NONE; +%ignore DBCHK_OK; +%ignore DBCHK_BAD; +%ignore DBCHK_NEW; +%ignore check_database; +%ignore open_database; +%ignore flush_buffers; +%ignore save_database; +%ignore close_database; +%ignore compress_btree; +%ignore get_input_file_from_archive; +%ignore loader_move_segm; +%ignore generate_ida_copyright; +%ignore is_in_loader; +%ignore get_ids_filename; + +// mem2base() has a custom wrapper +%ignore mem2base; + +%include "loader.hpp" + +// Custom wrapper for mem2base() +%rename (mem2base) mem2base_wrap; +%apply (char *STRING, int LENGTH) { (char *buf, int len) }; +%inline %{ +int mem2base_wrap(char *buf, int len, ea_t ea, long fpos) +{ + return mem2base((void *)buf, ea, ea+len, fpos); +} +%} + + + diff --git a/swig/moves.i b/swig/moves.i new file mode 100644 index 0000000..b4154b7 --- /dev/null +++ b/swig/moves.i @@ -0,0 +1,11 @@ + +// Ignore kernel only symbols +%ignore init_marks; +%ignore term_marks; +%ignore change_jumps_stack_format; +%ignore move_marks; +%ignore loc_gtag; +%ignore DEFINE_CURLOC_HELPERS; +%ignore DEFINE_LOCATION_HELPERS; + +%include "moves.hpp" \ No newline at end of file diff --git a/swig/nalt.i b/swig/nalt.i new file mode 100644 index 0000000..3f49336 --- /dev/null +++ b/swig/nalt.i @@ -0,0 +1,6 @@ +%ignore NALT_EA; +%ignore NALT_ULONG; + +#define NALT_EA() + +%include "nalt.hpp" diff --git a/swig/name.i b/swig/name.i new file mode 100644 index 0000000..16dd1ec --- /dev/null +++ b/swig/name.i @@ -0,0 +1,35 @@ +%cstring_output_maxstr_none(char *buf, int bufsize); + +%cstring_bounded_output(char *dstname, MAXSTR); +%cstring_bounded_output(char *buf, MAXSTR); + +// FIXME: These should be fixed +%ignore get_name_value; +%ignore append_struct_fields; +%ignore get_struct_operand; +%ignore debug_name_how_t; +%ignore set_debug_names; +%ignore set_debug_name; +%ignore get_debug_name; +%ignore del_debug_names; +%ignore get_debug_name_ea; +%ignore nameVa; + +// Unexported & kernel-only +%ignore get_short_name; +%ignore get_long_name; +%ignore get_colored_short_name; +%ignore get_colored_long_name; +%ignore addDummyName; +%ignore convert_debug_names_to_normal; +%ignore convert_name_formats; +%ignore showhide_name; +%ignore clear_lname_bit; +%ignore fix_new_name; +%ignore rename; +%ignore move_names; +%ignore is_exit_name; +%ignore dummy_name_ea; + +%include "name.hpp" + diff --git a/swig/offset.i b/swig/offset.i new file mode 100644 index 0000000..fb277df --- /dev/null +++ b/swig/offset.i @@ -0,0 +1,3 @@ +%ignore calc_probable_base; + +%include "offset.hpp" diff --git a/swig/pro.i b/swig/pro.i new file mode 100644 index 0000000..1bccf6c --- /dev/null +++ b/swig/pro.i @@ -0,0 +1,3 @@ +%ignore print_all_counters; + +%include "pro.h" diff --git a/swig/queue.i b/swig/queue.i new file mode 100644 index 0000000..f7e4947 --- /dev/null +++ b/swig/queue.i @@ -0,0 +1,12 @@ +// TODO: This could be wrapped. +%ignore QueueGet; + +// Kernel-only & unexported symbols +%ignore QueueDel; +%ignore init_queue; +%ignore save_queue; +%ignore term_queue; +%ignore move_problems; +%ignore queue_del; + +%include "queue.hpp" \ No newline at end of file diff --git a/swig/search.i b/swig/search.i new file mode 100644 index 0000000..c428ad1 --- /dev/null +++ b/swig/search.i @@ -0,0 +1,14 @@ +%apply int * OUTPUT { int *opnum }; + +// Do not generate overloaded versions for default arguments +%feature("compactdefaultargs") find_error; +%feature("compactdefaultargs") find_notype; +%feature("compactdefaultargs") find_void; +%feature("compactdefaultargs") find_imm; + +// FIXME: search() should be checked and enabled +%ignore search; +%ignore user2bin; + +%include "search.hpp" +%clear int *opnum; diff --git a/swig/segment.i b/swig/segment.i new file mode 100644 index 0000000..79be4b9 --- /dev/null +++ b/swig/segment.i @@ -0,0 +1,29 @@ +// FIXME: These could be fixed +%ignore getn_selector; +%ignore set_segment_translations; +%ignore del_segment_translations; +%ignore get_segment_translations; + +// Ignore functions with callbacks +%ignore enumerate_selectors; +%ignore enumerate_segments_with_selector; + +// Kernel-only +%ignore init_groups; +%ignore save_groups; +%ignore term_groups; +%ignore vset_segm_name; +%ignore get_segm_expr; +%ignore get_based_segm_expr; +%ignore createSegmentation; +%ignore initSegment; +%ignore save_segments; +%ignore termSegment; +%ignore DeleteAllSegments; +%ignore delete_debug_segments; +%ignore is_debugger_segm; +%ignore is_ephemeral_segm; +%ignore correct_address; + +%include "segment.hpp" + diff --git a/swig/srarea.i b/swig/srarea.i new file mode 100644 index 0000000..1465553 --- /dev/null +++ b/swig/srarea.i @@ -0,0 +1,21 @@ +// Ignore kernel-only symbols +%ignore createSRarea; +%ignore killSRareas; +%ignore delSRarea; +%ignore SRareaStart; +%ignore SRareaEnd; +%ignore repairSRarea; +%ignore SRinit; +%ignore SRterm; +%ignore SRsave; + +#define R_es 29 +#define R_cs 30 +#define R_ss 31 +#define R_ds 32 +#define R_fs 33 +#define R_gs 34 + +%feature("compactdefaultargs") splitSRarea1; + +%include "srarea.hpp" diff --git a/swig/strlist.i b/swig/strlist.i new file mode 100644 index 0000000..19413df --- /dev/null +++ b/swig/strlist.i @@ -0,0 +1,11 @@ +// Ignore kernel-only symbol + +%ignore strwinsetup_t::setup_strings_window; +%ignore strwinsetup_t::save_config; +%ignore strwinsetup_t::restore_config; + +%ignore move_strings; + + + +%include "strlist.hpp" diff --git a/swig/struct.i b/swig/struct.i new file mode 100644 index 0000000..c375615 --- /dev/null +++ b/swig/struct.i @@ -0,0 +1,14 @@ +// Kernel-only symbols +%ignore init_struc; +%ignore save_struc; +%ignore term_struc; + +%feature("compactdefaultargs") add_struc; + +%include "struct.hpp" +// Add a get_member() member function to struc_t. +// This helps to access the members array in the class. +%extend struc_t { + member_t * get_member(int index) { return &(self->members[index]); } +} + diff --git a/swig/typeconv.i b/swig/typeconv.i new file mode 100644 index 0000000..1c7a216 --- /dev/null +++ b/swig/typeconv.i @@ -0,0 +1,82 @@ +// Convert an incoming Python list to a tid_t[] array +%typemap(in) tid_t[ANY](tid_t temp[$1_dim0]) { + int i, len; + + if (!PySequence_Check($input)) + { + PyErr_SetString(PyExc_TypeError,"Expecting a sequence"); + return NULL; + } + + /* Cap the number of elements to copy */ + len = PySequence_Length($input) < $1_dim0 ? PySequence_Length($input) : $1_dim0; + + for (i =0; i < len; i++) + { + PyObject *o = PySequence_GetItem($input,i); + if (!PyLong_Check(o)) + { + Py_XDECREF(o); + PyErr_SetString(PyExc_ValueError,"Expecting a sequence of long integers"); + return NULL; + } + + temp[i] = PyLong_AsUnsignedLong(o); + Py_DECREF(o); + } + $1 = &temp[0]; +} + +%define %cstring_output_maxstr_none(TYPEMAP, SIZE) +%typemap (default) SIZE { + $1 = MAXSTR; +} +%typemap(in,numinputs=0) (TYPEMAP, SIZE) { +#ifdef __cplusplus + $1 = ($1_ltype) new char[MAXSTR+1]; +#else + $1 = ($1_ltype) malloc(MAXSTR+1); +#endif +} +%typemap(out) ssize_t { + /* REMOVING ssize_t return value in $symname */ +} +%typemap(argout) (TYPEMAP,SIZE) { + if (result > 0) + { + resultobj = PyString_FromString($1); + } + else + { + Py_INCREF(Py_None); + resultobj = Py_None; + } +#ifdef __cplusplus + delete [] $1; +#else + free($1); +#endif +} +%enddef + +%define %cstring_bounded_output_none(TYPEMAP,MAX) +%typemap(in, numinputs=0) TYPEMAP(char temp[MAX+1]) { + $1 = ($1_ltype) temp; +} +%typemap(argout,fragment="t_output_helper") TYPEMAP { + PyObject *o; + $1[MAX] = 0; + + if ($1 > 0) + { + o = PyString_FromString($1); + } + else + { + o = Py_None; + Py_INCREF(Py_None); + } + $result = t_output_helper($result,o); +} +%enddef + diff --git a/swig/typeinf.i b/swig/typeinf.i new file mode 100644 index 0000000..e9eef3e --- /dev/null +++ b/swig/typeinf.i @@ -0,0 +1,174 @@ +// Most of these could be wrapped if needed +%ignore get_cc; +%ignore get_cc_type_size; +%ignore set_argloc; +%ignore set_dt; +%ignore set_da; +%ignore set_de; +%ignore get_dt; +%ignore get_da; +%ignore get_de; +%ignore skip_ptr_type_header; +%ignore skip_array_type_header; +%ignore typend; +%ignore typlen; +%ignore typncpy; +%ignore tppncpy; +%ignore typcmp; +%ignore typdup; +%ignore equal_types; +%ignore resolve_typedef; +%ignore is_resolved_type_const; +%ignore is_resolved_type_void; +%ignore is_resolved_type_ptr; +%ignore is_resolved_type_func; +%ignore is_resolved_type_array; +%ignore is_resolved_type_complex; +%ignore is_resolved_type_struct; +%ignore is_resolved_type_union; +%ignore is_resolved_type_enum; +%ignore is_resolved_type_bitfld; +%ignore is_castable; +%ignore remove_constness; +%ignore remove_pointerness; +%ignore get_int_type_bit; +%ignore get_unk_type_bit; +%ignore tns; + +%ignore til_t::base; +%ignore til_t::syms; +%ignore til_t::types; +%ignore til_t::macros; + +%ignore add_base_tils; +%ignore sort_til; +%ignore til_add_macro; +%ignore til_next_macro; + +%ignore get_type_size; +%ignore get_type_size0; +%ignore skip_type; +%ignore get_pointer_object_size; + +%ignore descr_t; + +%ignore unpack_type; +%ignore print_type_to_one_line; +%ignore print_type_to_many_lines; +%ignore print_type; +%ignore show_type; +%ignore show_plist; + +%ignore extract_pstr; +%ignore extract_name; +%ignore skipName; +%ignore extract_comment; +%ignore skipComment; +%ignore extract_fargcmt; +%ignore skip_argloc; +%ignore extract_argloc; + +%ignore h2ti; +%ignore h2ti_warning; +%ignore parse_type; +%ignore parse_types; +%ignore get_named_type; + +%ignore set_named_type; +%ignore get_named_type_size; + +%ignore decorate_name; +%ignore gen_decorate_name; +%ignore calc_bare_name; +%ignore predicate_t; +%ignore choose_named_type; +%ignore get_default_align; +%ignore align_size; +%ignore align_size; +%ignore get_default_enum_size; +%ignore max_ptr_size; +%ignore based_ptr_name_and_size; +%ignore calc_arglocs; + +%ignore apply_type; +%ignore apply_callee_type; +%ignore guess_func_type; +%ignore guess_type; + +%ignore build_funcarg_arrays; +%ignore free_funcarg_arrays; +%ignore extract_func_ret_type; +%ignore calc_names_cmts; +%ignore resolve_complex_type; +%ignore foreach_strmem; +%ignore is_type_scalar; +%ignore get_type_signness; +%ignore is_type_signed; +%ignore is_type_unsigned; +%ignore get_struct_member; +%ignore idb_type_to_til; +%ignore get_idb_type; +%ignore apply_type_to_stkarg; +%ignore use_regarg_type_cb; +%ignore set_op_type_t; +%ignore is_stkarg_load_t; +%ignore has_delay_slot_t; +%ignore gen_use_arg_types; + +// Kernel-only symbols +%ignore init_til; +%ignore save_til; +%ignore term_til; +%ignore determine_til; +%ignore get_tilpath; +%ignore autoload_til; +%ignore get_idainfo_by_type; +%ignore apply_callee_type; +%ignore propagate_stkargs; +%ignore build_anon_type_name; +%ignore type_names; +%ignore get_compiler_id; + +%include "typeinf.hpp" + +// Custom wrappers + +%rename (load_til) load_til_wrap; +%inline %{ +til_t * load_til(const char *tildir, const char *name) +{ + char errbuf[4096]; + til_t *res; + + res = load_til(tildir, name, errbuf, sizeof(errbuf)); + + if (!res) + { + PyErr_SetString(PyExc_RuntimeError, errbuf); + return NULL; + } + + return res; +} +%} + +%rename (load_til_header_wrap) load_til_header_wrap; +%inline %{ +til_t * load_til_header_wrap(const char *tildir, const char *name) +{ + char errbuf[4096]; + til_t *res; + + res = load_til_header(tildir, name, errbuf, sizeof(errbuf));; + + if (!res) + { + PyErr_SetString(PyExc_RuntimeError, errbuf); + return NULL; + } + + return res; +} +%} + + diff --git a/swig/ua.i b/swig/ua.i new file mode 100644 index 0000000..cc11e17 --- /dev/null +++ b/swig/ua.i @@ -0,0 +1,27 @@ +// Include the patched header +// All the unchecked declarations are between +// #ifndef SWIG +%include "ua.hpp" + +// Small function to get the global cmd pointer +// In Python it returns an insn_t class instance +%inline { +insn_t * get_current_instruction() +{ + return &cmd; +} +} + +// Get the nth operand from the insn_t class +%inline { +op_t *get_instruction_operand(insn_t *ins, int n) +{ + if (!ins) + { + return NULL; + } + + return &(ins->Operands[n]); +} +} + diff --git a/swig/xref.i b/swig/xref.i new file mode 100644 index 0000000..e632091 --- /dev/null +++ b/swig/xref.i @@ -0,0 +1,22 @@ +// Ignore kernel-only functions and variables +%ignore create_xrefs_from; +%ignore create_xrefs_from_data; +%ignore delete_all_xrefs_from; +%ignore delete_data_xrefs_from; +%ignore delete_code_xrefs_from; +%ignore destroy_if_align; +%ignore lastXR; +%ignore has_jump_or_flow_xref; +%ignore has_call_xref; +%ignore destroy_switch_info; + +// These functions should not be called directly (according to docs) +%ignore xrefblk_t_first_from; +%ignore xrefblk_t_next_from; +%ignore xrefblk_t_first_to; +%ignore xrefblk_t_next_to; + +// 'from' is a reserved Python keyword +%rename (frm) from; + +%include "xref.hpp"