From 9b85915a484afa37b940ee51c3ec057f54ab1dad Mon Sep 17 00:00:00 2001 From: "gergely.erdelyi" Date: Sat, 20 Oct 2007 07:03:51 +0000 Subject: [PATCH] Initial SVN commit of version 0.9.54 sources. --- BUILDING.txt | 63 + CHANGES.txt | 72 + COPYING.txt | 27 + README.txt | 70 + STATUS.txt | 72 + basetsd.h | 4 + build.py | 408 +++ docs/notes.txt | 53 + examples/chooser.py | 46 + examples/ex1.idc | 35 + examples/ex1_idaapi.py | 29 + examples/ex1_idautils.py | 20 + patches/ida51.patch | 826 +++++ python.cpp | 461 +++ python/idautils.py | 268 ++ python/idc.py | 6123 ++++++++++++++++++++++++++++++++++++++ python/init.py | 135 + swig/auto.i | 13 + swig/bytes.i | 72 + swig/dbg.i | 10 + swig/diskio.i | 43 + swig/entry.i | 7 + swig/enum.i | 28 + swig/expr.i | 32 + swig/fixup.i | 6 + swig/frame.i | 20 + swig/funcs.i | 36 + swig/ida.i | 13 + swig/idaapi.i | 112 + swig/idp.i | 3 + swig/ints.i | 6 + swig/kernwin.i | 217 ++ swig/lines.i | 63 + swig/loader.i | 123 + swig/moves.i | 11 + swig/nalt.i | 6 + swig/name.i | 35 + swig/offset.i | 3 + swig/pro.i | 3 + swig/queue.i | 12 + swig/search.i | 14 + swig/segment.i | 29 + swig/srarea.i | 21 + swig/strlist.i | 11 + swig/struct.i | 14 + swig/typeconv.i | 82 + swig/typeinf.i | 174 ++ swig/ua.i | 27 + swig/xref.i | 22 + 49 files changed, 9980 insertions(+) create mode 100644 BUILDING.txt create mode 100644 CHANGES.txt create mode 100644 COPYING.txt create mode 100644 README.txt create mode 100644 STATUS.txt create mode 100644 basetsd.h create mode 100644 build.py create mode 100644 docs/notes.txt create mode 100644 examples/chooser.py create mode 100644 examples/ex1.idc create mode 100644 examples/ex1_idaapi.py create mode 100644 examples/ex1_idautils.py create mode 100644 patches/ida51.patch create mode 100644 python.cpp create mode 100644 python/idautils.py create mode 100644 python/idc.py create mode 100644 python/init.py create mode 100644 swig/auto.i create mode 100644 swig/bytes.i create mode 100644 swig/dbg.i create mode 100644 swig/diskio.i create mode 100644 swig/entry.i create mode 100644 swig/enum.i create mode 100644 swig/expr.i create mode 100644 swig/fixup.i create mode 100644 swig/frame.i create mode 100644 swig/funcs.i create mode 100644 swig/ida.i create mode 100644 swig/idaapi.i create mode 100644 swig/idp.i create mode 100644 swig/ints.i create mode 100644 swig/kernwin.i create mode 100644 swig/lines.i create mode 100644 swig/loader.i create mode 100644 swig/moves.i create mode 100644 swig/nalt.i create mode 100644 swig/name.i create mode 100644 swig/offset.i create mode 100644 swig/pro.i create mode 100644 swig/queue.i create mode 100644 swig/search.i create mode 100644 swig/segment.i create mode 100644 swig/srarea.i create mode 100644 swig/strlist.i create mode 100644 swig/struct.i create mode 100644 swig/typeconv.i create mode 100644 swig/typeinf.i create mode 100644 swig/ua.i create mode 100644 swig/xref.i 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"