├── .gitignore ├── AUTHORS.txt ├── BUILDING.txt ├── CONTRIBUTING.md ├── COPYING.txt ├── HOWTO.md ├── README.md ├── README_python3.txt ├── STATUS.txt ├── Scripts ├── 3rd │ └── BboeVt.py ├── AsmViewer.py ├── CallStackWalk.py ├── DbgCmd.py ├── DrvsDispatch.py ├── ExchainDump.py ├── FindInstructions.py ├── ImpRef.py ├── ImportExportViewer.py ├── PteDump.py ├── SEHGraph.py ├── VaDump.py ├── VirusTotal.py ├── callstack_test.py └── msdnapihelp.py ├── api-examples ├── api-examples-toc.md ├── func │ ├── decompile_func_and_callees.py │ ├── list_func_callees.py │ ├── print_location_info.py │ └── sort_func_by_calls.py ├── gdl │ └── colorize_graph_node.py ├── hexrays │ └── hr_decompile_func_and_callees.py ├── idb │ ├── frame_event_listener.py │ └── lt_event_listener.py ├── idp │ └── log_idp_events.py ├── inf │ ├── print_basic_info.py │ └── print_basic_info_plugin.py ├── misc │ └── find_binary_pattern.py ├── readme.md ├── segm │ └── list_imports.py └── typeinf │ ├── add_frame_member.py │ ├── apply_callee_tinfo.py │ ├── change_stkvar_name.py │ ├── change_stkvar_type.py │ ├── create_array.py │ ├── create_bfstruct.py │ ├── create_bmenum.py │ ├── create_libssh2_til.py │ ├── create_structs.py │ ├── create_user_shared_data.py │ ├── del_struct_members.py │ ├── func_ti_changed_listener.py │ ├── gap_size_align_snippet.py │ ├── import_type_from_til.py │ ├── insert_gap.py │ ├── list_enum_member.py │ ├── list_frame_info.py │ ├── list_func_details.py │ ├── list_stkvar_xrefs.py │ ├── list_struct_accesses.py │ ├── list_struct_member.py │ ├── list_struct_xrefs.py │ ├── list_union_member.py │ ├── mark_func_spoiled.py │ ├── operand_to_struct_member.py │ ├── setpehdr.py │ └── visit_tinfo.py ├── api_contents.brief ├── api_contents.full ├── build.py ├── copy_docs_to_p4.sh ├── docs ├── howto │ └── swig.md ├── inject_pydoc.md ├── notes.txt └── pydoc.md ├── examples-internal └── dirtree_missing_inode.py ├── examples ├── README.md ├── analysis │ └── dump_func_info.py ├── core │ ├── actions.py │ ├── add_hotkey.py │ ├── add_idc_hotkey.py │ ├── auto_instantiate_widget_plugin.py │ ├── colorize_disassembly.py │ ├── colorize_disassembly_on_the_fly.py │ ├── create_structure_programmatically.py │ ├── custom_cli.py │ ├── custom_data_types_and_formats.py │ ├── dump_extra_comments.py │ ├── dump_flowchart.py │ ├── dump_selection.py │ ├── extend_idc.py │ ├── find_string.py │ ├── idapythonrc.py │ ├── install_user_defined_prefix.py │ ├── list_bookmarks.py │ ├── list_function_items.py │ ├── list_imports.py │ ├── list_patched_bytes.py │ ├── list_problems.py │ ├── list_segment_functions.py │ ├── list_segment_functions_using_idautils.py │ ├── list_stkvar_xrefs.py │ ├── list_strings.py │ ├── produce_c_file.py │ ├── produce_lst_file.py │ ├── register_timer.py │ └── trigger_actions_programmatically.py ├── cvt64 │ └── py_cvt64_sample.py ├── debugging │ ├── appcall │ │ ├── simple_appcall_common.py │ │ ├── simple_appcall_linux.py │ │ ├── simple_appcall_win.py │ │ └── test_programs │ │ │ └── simple_appcall │ │ │ ├── makefile │ │ │ ├── simple_appcall.c │ │ │ ├── simple_appcall_linux32 │ │ │ ├── simple_appcall_linux64 │ │ │ ├── simple_appcall_win32.exe │ │ │ └── simple_appcall_win64.exe │ ├── dbghooks │ │ ├── automatic_steps.py │ │ └── dbg_trace.py │ ├── misc │ │ ├── print_call_stack.py │ │ ├── print_registers.py │ │ └── registers_context_menu.py │ └── show_debug_names.py ├── hexrays │ ├── colorize_pseudocode_lines.py │ ├── curpos_details.py │ ├── decompile_entry_points.py │ ├── vds1.py │ ├── vds10.py │ ├── vds11.py │ ├── vds12.py │ ├── vds13.py │ ├── vds17.py │ ├── vds19.py │ ├── vds21.py │ ├── vds3.py │ ├── vds4.py │ ├── vds5.py │ ├── vds6.py │ ├── vds7.py │ ├── vds8.py │ ├── vds_create_hint.py │ ├── vds_hooks.py │ ├── vds_modify_user_lvars.py │ └── vds_xrefs.py ├── idbhooks │ ├── log_idb_events.py │ ├── operand_changed.py │ └── replay_prototypes_changes.py ├── idbs │ ├── be_ornot_be.i64 │ └── be_ornot_be.idb ├── idphooks │ ├── ana_emu_out.py │ └── assemble.py ├── index.css ├── index.html ├── index.js ├── index.md ├── merge │ ├── py_mex1.py │ └── py_mex3.py ├── pyqt │ ├── inject_command.py │ ├── paint_over_graph.py │ ├── paint_over_navbar.py │ └── populate_pluginform_with_pyqt_widgets.py ├── uihooks │ ├── func_chooser_coloring.py │ ├── lines_rendering.py │ ├── log_misc_events.py │ └── prevent_jump.py └── widgets │ ├── forms │ └── askusingform.py │ ├── graphs │ ├── custom_graph_with_actions.py │ └── sync_two_graphs.py │ ├── idaview │ └── wrap_idaview.py │ ├── listings │ ├── custom_viewer.py │ ├── jump_next_comment.py │ └── save_and_restore_listing_pos.py │ ├── misc │ └── add_menus.py │ ├── tabular_views │ ├── custom │ │ ├── choose.py │ │ ├── choose_multi.py │ │ ├── chooser_with_folders.py │ │ ├── func_chooser.py │ │ └── lazy_loaded_chooser.py │ └── string_window │ │ └── show_selected_strings.py │ └── waitbox │ └── show_and_hide_waitbox.py ├── extapi.cpp ├── extapi.hpp ├── idaapi.i ├── idapython.cfg ├── idapython.cpp ├── idapython.png ├── idapython.script ├── idapython_implib.def ├── makedep.cfg ├── makefile ├── options.lnt ├── out_of_tree └── parsed_notifications.zip ├── python ├── idaapi.py ├── idadex.py ├── idautils.py ├── idc.py ├── init.py └── lumina_model.py ├── pywraps.cpp ├── pywraps.hpp ├── pywraps ├── py_bytes.hpp ├── py_bytes_custdata.hpp ├── py_bytes_custdata.py ├── py_bytes_find_bytes.hpp ├── py_bytes_find_bytes.py ├── py_dbg.hpp ├── py_dbg.py ├── py_diskio.hpp ├── py_expr.hpp ├── py_expr.py ├── py_fpro.hpp ├── py_fpro_end.py ├── py_frame.hpp ├── py_funcs.hpp ├── py_funcs.py ├── py_gdl.py ├── py_graph.hpp ├── py_graph.py ├── py_hexrays.hpp ├── py_hexrays.py ├── py_hexrays_hooks.hpp ├── py_ida.py ├── py_idaapi.hpp ├── py_idaapi.py ├── py_idaapi_loader_input.hpp ├── py_idc.hpp ├── py_idd.hpp ├── py_idd.py ├── py_idp.hpp ├── py_idp.py ├── py_idp_idbhooks.hpp ├── py_idp_idbhooks.py ├── py_idp_notify_when.py ├── py_ieee.hpp ├── py_ieee.py ├── py_kernwin.hpp ├── py_kernwin.py ├── py_kernwin_askform.hpp ├── py_kernwin_askform.py ├── py_kernwin_choose.hpp ├── py_kernwin_choose.py ├── py_kernwin_cli.hpp ├── py_kernwin_cli.py ├── py_kernwin_custview.hpp ├── py_kernwin_custview.py ├── py_kernwin_end.py ├── py_kernwin_idaview.hpp ├── py_kernwin_idaview.py ├── py_kernwin_plgform.hpp ├── py_kernwin_plgform.py ├── py_kernwin_viewhooks.hpp ├── py_kernwin_viewhooks.py ├── py_lines.hpp ├── py_lines.py ├── py_loader.hpp ├── py_lumina.hpp ├── py_lumina.py ├── py_moves.hpp ├── py_moves.py ├── py_moves_end.py ├── py_nalt.hpp ├── py_nalt.py ├── py_name.hpp ├── py_name.py ├── py_netnode_end.py ├── py_pro.hpp ├── py_pro.py ├── py_range.hpp ├── py_range.py ├── py_registry.hpp ├── py_search.hpp ├── py_search.py ├── py_segment.hpp ├── py_typeinf.hpp ├── py_typeinf.py ├── py_ua.hpp ├── py_ua.py ├── py_xref.hpp ├── py_xref.py ├── pywraps.hpp ├── pywraps.sln └── pywraps.vcproj ├── stublib ├── makelibpython3-stub.sh ├── makelibpython3.sh ├── makestub2.py └── readme.txt ├── swig ├── allins.i ├── auto.i ├── bitrange.i ├── bytes.i ├── dbg.i ├── dirtree.i ├── diskio.i ├── entry.i ├── expr.i ├── fixup.i ├── fpro.i ├── frame.i ├── funcs.i ├── gdl.i ├── graph.i ├── hexrays.i ├── ida.i ├── idaapi.i ├── idbhooks.i ├── idc.i ├── idd.i ├── idp.i ├── ieee.i ├── kernwin.i ├── lines.i ├── linput.i ├── loader.i ├── lumina.i ├── merge.i ├── mergemod.i ├── micro.org ├── moves.i ├── nalt.i ├── name.i ├── netnode.i ├── offset.i ├── pro.i ├── problems.i ├── range.i ├── regfinder.i ├── registry.i ├── search.i ├── segment.i ├── segregs.i ├── srclang.i ├── strlist.i ├── tryblks.i ├── typeinf.i ├── ua.i ├── undo.i └── xref.i ├── tbd.md ├── test_pywraps.cpp ├── test_pywraps.ini ├── test_pywraps32.txt ├── test_pywraps64.txt └── tools ├── chkapi.py ├── collect_traces.py ├── collected_traces.txt ├── compare_traces.py ├── deploy.py ├── deploy └── header.i.in ├── docs ├── epytext.py ├── hrdoc.css ├── hrdoc.py └── templates │ ├── config.mako │ ├── credits.mako │ ├── head.mako │ ├── html.mako │ ├── index.mako │ └── md.mako ├── doxygen_utils.py ├── examples_index_template.html ├── examples_index_template.md ├── funlines.py ├── gen_examples_index.cfg ├── gen_examples_index.py ├── genhooks ├── all_recipes.py ├── doxy_gen_notifs.cfg.in ├── gendoxycfg.py ├── genhooks.py ├── recipe_dbghooks.py ├── recipe_hexrays.py ├── recipe_idbhooks.py ├── recipe_idphooks.py ├── recipe_uihooks.py └── recipe_viewhooks.py ├── genidaapi.py ├── genswigheader.py ├── hooks_utils.py ├── inject_pydoc.py ├── inject_pydoc ├── bytes.py └── idp.py ├── inject_pydoc_cases.txt ├── inspect.py ├── patch_codegen.py ├── patch_codegen ├── bytes.py ├── dbg.py ├── dirtree.py ├── diskio.py ├── expr.py ├── fpro.py ├── funcs.py ├── graph.py ├── hexrays.py ├── hexrays_h.py ├── ida_hexrays.py ├── idp.py ├── kernwin.py ├── lines.py ├── merge.py ├── nalt.py ├── pro.py ├── typeinf.py └── typeinf_batch.py ├── patch_constants.py ├── patch_directors_cc.py ├── patch_h_codegen.py ├── patch_python_codegen.py ├── preprocess_sdk_header.py ├── py_scanner.py ├── pydoc.py ├── pydoc_data ├── __init__.py ├── _pydoc.css └── topics.py ├── split_hexrays_templates.py ├── typemaps-supplement └── pymacros.swg └── wrapper_utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | obj/ 2 | *.pyc 3 | idapyswitch* 4 | fuzzer/ 5 | .vscode/ 6 | -------------------------------------------------------------------------------- /AUTHORS.txt: -------------------------------------------------------------------------------- 1 | The IDAPython Team: 2 | 3 | * Gergely Erdelyi - http://d-dome.net/idapython/ 4 | 5 | Original IDAPython author - The IDAPython Guy - 6 | 7 | 8 | * Hex-Rays - http://www.hex-rays.com/ - 9 | 10 | Hex-Rays joined the IDAPython project in September 2009 and started contributing. 11 | It is primarily maintained, updated and improved by Arnaud Diederen of Hex-Rays. 12 | 13 | * Elias Bachaalany - elias.bachaalany@gmail.com 14 | Maintains IDAPython online source code repository and coordinates patches/updates/contributions from Hex-Rays and 3rd party contributors 15 | 16 | 17 | * Ero Carrera - http://dkbza.org/ 18 | 19 | Project contributor 20 | 21 | 22 | * Special thanks to the following people for their contribution, suggestions and bug fixes: 23 | 24 | Igor Skochinsky 25 | Sebastian Muniz 26 | cbwhiz 27 | Arnaud Diederen 28 | -------------------------------------------------------------------------------- /COPYING.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2004-2010 Gergely Erdelyi . All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | 3. The name of the author may not be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 21 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 25 | OF SUCH DAMAGE. 26 | 27 | 28 | -------------------------------------------------------------------------------- /HOWTO.md: -------------------------------------------------------------------------------- 1 | # Developing IDAPython: best practices 2 | 3 | ### Rule of thumb 4 | 5 | If you are doing something non-trivial in IDAPython, or if you added something 6 | to the C++ SDK which will then be reflected in IDAPython, an *immensely* 7 | useful rule-of-thumb is to perform a diff of the autogenerated SWiG wrappers. 8 | 9 | Typically: 10 | `cp -R obj/x64_linux_gcc_32/3/wrappers/ /tmp/wrappers-before` 11 | 12 | `git diff /tmp/wrappers-before/ obj/x64_linux_gcc_32/3/wrappers/` 13 | 14 | It is always useful to make sure that SWiG did the right thing -- *especially* 15 | when modifying typemaps, but not only. 16 | 17 | ### How to add new module? 18 | 19 | We use the "zzz" placeholder for a module name in this "how-to". 20 | 21 | 1. create file swig/zzz.i 22 | ``` 23 | %{ 24 | #include 25 | %} 26 | %include "zzz.hpp" 27 | ``` 28 | 29 | 2. add zzz to the `MODULES_NAMES` var in makefile 30 | 31 | 3. add zzz to `SDK_FILES` var in etc/sdk/sdk_files.mak 32 | 33 | 4. add a line to python/idc.py if you want to autoload this module 34 | ``` 35 | import ida_zzz 36 | ``` 37 | 38 | 5. build 39 | 40 | 6. update the content of api_contents.txt 41 | (from obj/.../api_contents.txt.new) 42 | 43 | 7. rebuild 44 | 45 | 8. update the content of pydoc_injections.txt 46 | (from obj/.../pydoc_injections.txt) 47 | -------------------------------------------------------------------------------- /README_python3.txt: -------------------------------------------------------------------------------- 1 | IDAPython requires a Python3.x installation in order to work. 2 | 3 | Because different users might have different (and possibly multiple) 4 | versions of Python3.x installed, IDA comes with a tool called `idapyswitch` 5 | that can be run to select the desired Python3.x runtime. 6 | 7 | If you selected IDAPython-for-Python3.x at the installation time, 8 | the `idapyswitch` utility should already have been run and selected 9 | the most appropriate Python3.x version. 10 | 11 | Should you want to switch to another Python3.x install after installation, 12 | please run `idapyswitch` from the IDA directory. It will scan for Python 13 | installs present in the system's standard locations and offer you to choose one. 14 | It also supports optional command-line switches to handle non-standard installs. 15 | Run `idapyswitch -h` to see them. 16 | -------------------------------------------------------------------------------- /STATUS.txt: -------------------------------------------------------------------------------- 1 | Status of the IDC layer 2 | ----------------------- 3 | 4 | The IDC emulation layer is complete and at par with IDA 5.1, 5 | although it would benefit from more testing. 6 | 7 | 8 | Status of IDA API wrappers 9 | -------------------------- 10 | 11 | COMPLETE: all possible functions wrapped, no SWIG ifdefs 12 | INCOMPLETE: some wrapping or SWIG ifdefs still left 13 | EXCLUDED: will not be wrapped 14 | 15 | allins.hpp - COMPLETE 16 | range.hpp - COMPLETE (necessary SWIGdefs) 17 | auto.hpp - COMPLETE 18 | bytes.hpp - COMPLETE (some minor unwrapped) 19 | compress.hpp - EXCLUDED 20 | dbg.hpp - INCOMPLETE (SWIGs and lot of fixing to do) 21 | demangle.hpp - EXCLUDED 22 | diskio.hpp - INCOMPLETE (no SWIGs, some unwrapped) 23 | entry.hpp - COMPLETE 24 | err.h - EXCLUDED 25 | exehdr.h - EXCLUDED 26 | expr.hpp - COMPLETE (necessary SWIGs) 27 | fixup.hpp - COMPLETE 28 | fpro.h - EXCLUDED 29 | frame.hpp - COMPLETE 30 | funcs.hpp - COMPLETE (necessary SWIGs, minor FIXME) 31 | gdl.hpp - EXCLUDED 32 | graph.hpp - INCOMPLETE 33 | help.h - EXCLUDED 34 | ida.hpp - COMPLETE 35 | idd.hpp - COMPLETE (necessary SWIGs) 36 | idp.hpp - COMPLETE 37 | ieee.h - EXCLUDED 38 | intel.hpp - EXCLUDED 39 | kernwin.hpp - INCOMPLETE (SWIGs and lot of fixing to do) 40 | lex.hpp - EXCLUDED 41 | lines.hpp - INCOMPLETE (few FIXMEs) 42 | llong.hpp - EXCLUDED 43 | loader.hpp - INCOMPLETE (few FIXMEs) 44 | md5.h - EXCLUDED 45 | moves.hpp - COMPLETE (some needed SWIGs) 46 | nalt.hpp - INCOMPLETE (SWIGs and lot of fixing to do) 47 | name.hpp - INCOMPLETE (few FIXMEs) 48 | netnode.hpp - COMPLETE 49 | offset.hpp - COMPLETE 50 | prodir.h - EXCLUDED 51 | pro.h - COMPLETE (some needed SWIGs) 52 | queue.hpp - INCOMPLETE (one FIXME) 53 | regex.h - EXCLUDED 54 | search.hpp - COMPLETE 55 | segment.hpp - COMPLETE 56 | sistack.hpp - EXCLUDED 57 | segregs.hpp - INCOMPLETE (not wrapped at all) 58 | strlist.hpp - COMPLETE 59 | typeinf.hpp - INCOMPLETE (no SWIGs, lot of fixing to do) 60 | ua.hpp - INCOMPLETE (SWIGs and lot of fixing to do) 61 | va.hpp - EXCLUDED 62 | vm.hpp - EXCLUDED 63 | xref.hpp - COMPLETE 64 | -------------------------------------------------------------------------------- /Scripts/ExchainDump.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | This script shows how to send debugger commands and use the result in IDA 4 | 5 | Copyright (c) 1990-2024 Hex-Rays 6 | ALL RIGHTS RESERVED. 7 | 8 | """ 9 | from __future__ import print_function 10 | 11 | import re 12 | 13 | import ida_kernwin 14 | 15 | # class to store parsed results 16 | class exchain: 17 | def __init__(self, m): 18 | self.name = m.group(1) 19 | self.addr = int(m.group(2), 16) 20 | 21 | # Chooser class 22 | class MyChoose(ida_kernwin.Choose): 23 | def __init__(self, title, items): 24 | ida_kernwin.Choose.__init__(self, title, [ ["Address", 16], ["Name", 250] ]) 25 | self.items = items 26 | 27 | def OnGetLine(self, n): 28 | o = self.items[n] 29 | return ["%08X" % o.addr, o.name] 30 | 31 | def OnGetSize(self): 32 | return len(self.items) 33 | 34 | def OnSelectLine(self, n): 35 | ida_kernwin.jumpto(self.items[n].addr) 36 | return (ida_kernwin.Choose.NOTHING_CHANGED, ) 37 | 38 | def main(): 39 | ok, s = ida_dbg.send_dbg_command("!exchain") 40 | if not ok: 41 | return (False, "Cannot execute the command (%s)" % s) 42 | 43 | matches = re.finditer(r'[^:]+: ([^\(]+) \(([^\)]+)\)\n', s) 44 | entries = [exchain(x) for x in matches] 45 | if not entries: 46 | return (False, "Nothing to display: Could parse the result!") 47 | 48 | # Show a list of results, and let the user possibly jump to one of those 49 | chooser = MyChoose("Exchain choose", entries) 50 | chooser.Show() 51 | return (True, "Success!") 52 | 53 | ok, r = main() 54 | if not ok: 55 | print(r) 56 | -------------------------------------------------------------------------------- /Scripts/ImpRef.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | # ----------------------------------------------------------------------- 3 | # This is an example illustrating how to enumerate all addresses 4 | # that refer to all imported functions in a given module 5 | # 6 | # (c) Hex-Rays 7 | # 8 | import re 9 | 10 | import ida_kernwin 11 | import ida_nalt 12 | import ida_funcs 13 | 14 | import idautils 15 | 16 | # ----------------------------------------------------------------------- 17 | def find_imported_funcs(dllname): 18 | def imp_cb(ea, name, ord): 19 | if not name: 20 | name = '' 21 | imports.append([ea, name, ord]) 22 | return True 23 | 24 | imports = [] 25 | nimps = ida_nalt.get_import_module_qty() 26 | for i in range(0, nimps): 27 | name = ida_nalt.get_import_module_name(i) 28 | if re.match(dllname, name, re.IGNORECASE) is None: 29 | continue 30 | ida_nalt.enum_import_names(i, imp_cb) 31 | 32 | return imports 33 | 34 | 35 | # ----------------------------------------------------------------------- 36 | def find_import_ref(dllname): 37 | imports = find_imported_funcs(dllname) 38 | R = dict() 39 | for i, (ea, name,_) in enumerate(imports): 40 | #print("%x -> %s" % (ea, name)) 41 | for xref in idautils.XrefsTo(ea): 42 | # check if referrer is a thunk 43 | ea = xref.frm 44 | f = ida_funcs.get_func(ea) 45 | if f and (f.flags & ida_funcs.FUNC_THUNK) != 0: 46 | imports.append([f.start_ea, ida_funcs.get_func_name(f.start_ea), 0]) 47 | #print("\t%x %s: from a thunk, parent added %x" % (ea, name, f.start_ea)) 48 | continue 49 | 50 | # save results 51 | if i not in R: 52 | R[i] = [] 53 | 54 | R[i].append(ea) 55 | 56 | return (imports, R) 57 | 58 | # ----------------------------------------------------------------------- 59 | def main(): 60 | dllname = ida_kernwin.ask_str('kernel32', 0, "Enter module name") 61 | if not dllname: 62 | print("Cancelled") 63 | return 64 | 65 | imports, R = find_import_ref(dllname) 66 | for k, v in R.items(): 67 | print(imports[k][1]) 68 | for ea in v: 69 | print("\t%x" % ea) 70 | 71 | # ----------------------------------------------------------------------- 72 | main() 73 | -------------------------------------------------------------------------------- /Scripts/callstack_test.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import sys 3 | import os 4 | 5 | def __sys(cmd, fmt=None, echo=True): 6 | """Executes a string of OS commands and returns the a list of tuples (return code,command executed)""" 7 | if not fmt: 8 | fmt = {} 9 | r = [] 10 | for cmd in [x for x in (cmd % fmt).split("\n") if len(x)]: 11 | if echo: 12 | print(">>>", cmd) 13 | r.append((os.system(cmd), cmd)) 14 | return r 15 | 16 | body = r"""/// Autogenerated file 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | void want_break(int n) 23 | { 24 | printf("do you want to DebugBreak in func%d()?", n); 25 | char ch = _toupper(_getch()); 26 | printf("\n"); 27 | if (ch == 'Y') 28 | DebugBreak(); 29 | else if (ch == 'X') 30 | ExitProcess(n); 31 | } 32 | %FUNCS% 33 | int main(int /*argc*/, char * /*argv[]*/) 34 | { 35 | func1(); 36 | return 0; 37 | } 38 | """ 39 | 40 | funcs_body = [] 41 | 42 | func_body = r""" 43 | void func%(n)d() 44 | { 45 | printf("%(ident)senter %(n)d\n");%(pause)s 46 | func%(n1)d(); 47 | printf("%(ident)sleave %(n)d\n"); 48 | } 49 | """ 50 | 51 | if len(sys.argv) < 2: 52 | print("usage: gen nb_calls pause_frequency") 53 | sys.exit(0) 54 | 55 | n = int(sys.argv[1]) 56 | if n < 1: 57 | print("at least one call should be passed!") 58 | sys.exit(1) 59 | 60 | m = int(sys.argv[2]) 61 | 62 | func_params = {'n': 0, 'n1': 0, 'ident': '', 'pause' : ''} 63 | 64 | for i in range(1, n + 1): 65 | func_params['n'] = i 66 | func_params['n1'] = i+1 67 | func_params['ident'] = " " * i 68 | func_params['pause'] = ("\n want_break(%d);" % i) if (i % m) == 0 else '' 69 | 70 | funcs_body.append(func_body % func_params) 71 | funcs_body.append(r""" 72 | void func%(n)d() 73 | { 74 | printf("that's it #%(n)d!\n"); 75 | } 76 | """ % {'n':i+1}) 77 | funcs_body.reverse() 78 | 79 | # write the file 80 | body = body.replace('%FUNCS%', ''.join(funcs_body)) 81 | f = file('src.cpp', 'w') 82 | f.write(body) 83 | f.close() 84 | 85 | __sys(""" 86 | if exist src.exe del src.exe 87 | bcc32 src 88 | if exist src.exe move src.exe src_bcc.exe 89 | if exist src.obj del src.obj 90 | cl32 src.cpp /Zi /Od 91 | """) 92 | -------------------------------------------------------------------------------- /api-examples/api-examples-toc.md: -------------------------------------------------------------------------------- 1 | # API examples 2 | 3 | 4 | This file contains the list of all the IDA python examples. 5 | 6 | 7 | ## func 8 | 9 | * decompile_func_and_callees.py 10 | * list_func_callees.py 11 | * print_location_info.py 12 | * sort_func_by_calls.py 13 | 14 | ## gdl 15 | 16 | * colorize_graph_node.py 17 | 18 | ## hexrays 19 | 20 | * hr_decompile_func_and_callees.py 21 | 22 | ## idb 23 | 24 | * frame_event_listener.py 25 | * lt_event_listener.py 26 | 27 | ## idp 28 | 29 | * log_idp_events.py 30 | 31 | ## inf 32 | 33 | * print_basic_info.py 34 | * print_basic_info_plugin.py 35 | 36 | ## misc 37 | 38 | * find_binary_pattern.py 39 | 40 | ## segm 41 | 42 | * list_imports.py 43 | 44 | ## typeinf 45 | 46 | * add_frame_member.py 47 | * apply_callee_tinfo.py 48 | * change_stkvar_name.py 49 | * change_stkvar_type.py 50 | * create_array.py 51 | * create_bfstruct.py 52 | * create_bmenum.py 53 | * create_libssh2_til.py 54 | * create_structs.py 55 | * create_user_shared_data.py 56 | * del_struct_members.py 57 | * func_ti_changed_listener.py 58 | * gap_size_align_snippet.py 59 | * import_type_from_til.py 60 | * insert_gap.py 61 | * list_enum_member.py 62 | * list_frame_info.py 63 | * list_func_details.py 64 | * list_stkvar_xrefs.py 65 | * list_struct_accesses.py 66 | * list_struct_member.py 67 | * list_struct_xrefs.py 68 | * list_union_member.py 69 | * mark_func_spoiled.py 70 | * operand_to_struct_member.py 71 | * setpehdr.py 72 | * visit_tinfo.py 73 | -------------------------------------------------------------------------------- /api-examples/func/decompile_func_and_callees.py: -------------------------------------------------------------------------------- 1 | import idautils 2 | import ida_kernwin 3 | import ida_funcs 4 | import ida_ua 5 | import ida_allins 6 | import ida_ida 7 | import ida_hexrays 8 | import ida_lines 9 | import idc 10 | 11 | def build_function_list(func): 12 | func_list = [] 13 | 14 | items = ida_funcs.func_item_iterator_t(func) 15 | for item in items: 16 | is_jmp = False 17 | 18 | insn = ida_ua.insn_t() 19 | if not ida_ua.decode_insn(insn, item): 20 | continue 21 | 22 | if not insn.itype == ida_allins.NN_call and not insn.itype == ida_allins.NN_jmp: 23 | continue 24 | 25 | if insn.itype == ida_allins.NN_jmp: 26 | is_jmp = True 27 | 28 | for xref in idautils.CodeRefsFrom(item, 0): 29 | callee = ida_funcs.get_func(xref) 30 | if not callee: 31 | print(f'Unable to retrieve function object for {xref:x}. Skipping.') 32 | continue 33 | 34 | if is_jmp and callee.start_ea == func.start_ea: 35 | continue 36 | 37 | if callee not in func_list: 38 | func_list.append(callee) 39 | 40 | return func_list 41 | 42 | 43 | def print_pseudo_code(cfunc): 44 | sv = cfunc.get_pseudocode() 45 | for sline in sv: 46 | print(ida_lines.tag_remove(sline.line)) 47 | print('') 48 | 49 | 50 | def decompile_and_print(func): 51 | func_list = build_function_list(func) 52 | func_list = [func, *func_list] 53 | 54 | for item in func_list: 55 | cfunc = ida_hexrays.decompile(item) 56 | if not cfunc: 57 | print(f'Unable to decompile function {ida_funcs.get_func_name(item.start_ea)}') 58 | return False 59 | print_pseudo_code(cfunc) 60 | 61 | 62 | def main(): 63 | if not ida_ida.inf_get_procname() == 'metapc': 64 | return False 65 | 66 | if not ida_hexrays.init_hexrays_plugin(): 67 | return False 68 | 69 | func = ida_funcs.get_func(idc.here()) 70 | if not func: 71 | print('Please put the cursor inside a function and retry.') 72 | 73 | decompile_and_print(func) 74 | 75 | ida_kernwin.msg_clear() 76 | main() -------------------------------------------------------------------------------- /api-examples/func/list_func_callees.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: List all the functions called by the one in which the 3 | cursor is currently located. 4 | 5 | description: 6 | If the cursor is located inside a function: 7 | * get the function object 8 | * get the function name 9 | * get a function item iterator 10 | * iterate through the items, and for each one decode it 11 | * if the item is a call get the address of the callee 12 | - get its name 13 | - display its name its address and address of the call. 14 | * if no calle is found print a statement indicating this fact. 15 | """ 16 | import idautils 17 | import ida_kernwin 18 | import ida_funcs 19 | import ida_ua 20 | import ida_allins 21 | import ida_ida 22 | import idc 23 | 24 | ida_kernwin.msg_clear() 25 | 26 | if ida_ida.inf_get_procname() == 'metapc': 27 | func = ida_funcs.get_func(idc.here()) 28 | if func: 29 | has_callee = False 30 | func_name = ida_funcs.get_func_name(func.start_ea) 31 | if not func_name: 32 | func_name = hex(func.start_ea) 33 | print(f'Function {func_name} [{func.start_ea:x}] calls:') 34 | 35 | items = ida_funcs.func_item_iterator_t(func) 36 | for item in items: 37 | insn = ida_ua.insn_t() 38 | if not ida_ua.decode_insn(insn, item): 39 | continue 40 | 41 | if not insn.itype == ida_allins.NN_call: 42 | continue 43 | 44 | if not has_callee: 45 | has_callee = True 46 | 47 | for xref in idautils.CodeRefsFrom(item, 0): 48 | print(f'\t- {ida_funcs.get_func_name(xref)} [{xref:x}] @{item:x}') 49 | 50 | if not has_callee: 51 | print('\t- no function.') 52 | else: 53 | print('Please place the cursor inside a function and retry.') 54 | else: 55 | print('This script will propely work for "metapc" procmod only.') 56 | -------------------------------------------------------------------------------- /api-examples/func/print_location_info.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Print argument location information. 3 | 4 | description: 5 | In this script, we iterate through a function 6 | arguments and display information about their 7 | location and size. For this we: 8 | * get the function type information 9 | * iterate through the arguments 10 | * for each of them we print its location (register or stack), 11 | offset (if in stack) and size 12 | """ 13 | import ida_nalt 14 | import ida_funcs 15 | import ida_typeinf 16 | import idc 17 | import ida_kernwin 18 | 19 | def print_argument_locations(func): 20 | tif = ida_typeinf.tinfo_t() 21 | if ida_nalt.get_tinfo(tif, func.start_ea): 22 | fi = ida_typeinf.func_type_data_t() 23 | if tif.get_func_details(fi): 24 | if fi.size(): 25 | print('Argument location:') 26 | for item in fi: 27 | if item.name: 28 | ida_kernwin.msg(f'\t{item.name}: ') 29 | else: 30 | ida_kernwin.msg(f'\t????: ') 31 | location = ida_typeinf.print_argloc(item.argloc) 32 | if location: 33 | ida_kernwin.msg(f'{location}.') 34 | elif item.argloc.in_stack: 35 | ida_kernwin.msg(f'stack({item.argloc.stkoff():x}).') 36 | print(f'{item.type.get_size()}') 37 | else: 38 | print('No arguments') 39 | else: 40 | print('Problems retrieving function details') 41 | else: 42 | print('Problem retrieving function type info.') 43 | 44 | 45 | if __name__ == '__main__': 46 | func = ida_funcs.get_func(idc.here()) 47 | if not func: 48 | print('Place the cursor inside a function and retry.') 49 | else: 50 | print_argument_locations(func) -------------------------------------------------------------------------------- /api-examples/func/sort_func_by_calls.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Print the list of the functions in the currently loaded 3 | IDB sorted (descending) by the number of code reference to 4 | each of them. 5 | 6 | description: 7 | In this script, we iterate through the list of function entry 8 | points and fore each of them we: 9 | * get its name 10 | * get the number of code reference made to it 11 | * put it in the map. 12 | Once done we: 13 | * sort the map in descending number of calls 14 | * print it. 15 | """ 16 | import ida_kernwin 17 | import ida_funcs 18 | import idc 19 | import idautils 20 | 21 | ida_kernwin.msg_clear() 22 | 23 | func_map = {} 24 | for funcea in idautils.Functions(): 25 | func_name = ida_funcs.get_func_name(funcea) 26 | if not func_name: 27 | func_name = hex(funcea) 28 | else: 29 | func_name = idc.demangle_name(func_name, idc.get_inf_attr(idc.INF_LONG_DN)) 30 | call_count = 0 31 | for xref in idautils.CodeRefsTo(funcea, 1): 32 | call_count += 1 33 | if call_count: 34 | func_map[func_name] = call_count 35 | 36 | func_map_by_calls = sorted(func_map.items(), key=lambda x:x[1], reverse=True) 37 | for func, calls in func_map_by_calls: 38 | print(f'{func} called {calls} time(s)') 39 | -------------------------------------------------------------------------------- /api-examples/gdl/colorize_graph_node.py: -------------------------------------------------------------------------------- 1 | import ida_graph 2 | import ida_funcs 3 | import ida_gdl 4 | import ida_kernwin 5 | import idc 6 | 7 | func = ida_funcs.get_func(idc.here()) 8 | qflow = ida_gdl.qflow_chart_t("", func, 0, 0, 0) 9 | for n in range(qflow.size()): 10 | node = qflow[n] 11 | print(f'Start ea : {node.start_ea:x}, end ea: {node.end_ea:x}, index: {n}') 12 | ni = ida_graph.node_info_t() 13 | ni.bg_color = 0xFF00 14 | ida_graph.set_node_info(func.start_ea, n, ni, ida_graph.NIF_BG_COLOR) 15 | ida_kernwin.refresh_idaview_anyway() -------------------------------------------------------------------------------- /api-examples/hexrays/hr_decompile_func_and_callees.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Python plugin that decompiles a function and its callees. 3 | 4 | description: 5 | This script does the same as decompile_func_and_callee but instead 6 | of using the cross-references, uses a ctree visitor to build the 7 | list of callees. 8 | """ 9 | import ida_hexrays 10 | import ida_lines 11 | import ida_funcs 12 | import ida_kernwin 13 | 14 | 15 | def find_calls(cfunc): 16 | class finder_t(ida_hexrays.ctree_visitor_t): 17 | def __init__(self): 18 | ida_hexrays.ctree_visitor_t.__init__(self, ida_hexrays.CV_FAST | ida_hexrays.CV_INSNS) 19 | 20 | self.results = [] 21 | return 22 | 23 | def visit_insn(self, inst): 24 | if inst.op == ida_hexrays.cit_expr and inst.cexpr.op == ida_hexrays.cot_call: 25 | self.results.append(inst.cexpr.x.obj_ea) 26 | return 0 27 | 28 | finder = finder_t() 29 | finder.apply_to(cfunc.body, None) 30 | return finder.results 31 | 32 | 33 | def print_pseudo_code(cfunc): 34 | sv = cfunc.get_pseudocode(); 35 | for sline in sv: 36 | print(ida_lines.tag_remove(sline.line)) 37 | 38 | 39 | def main(): 40 | if not ida_hexrays.init_hexrays_plugin(): 41 | return False 42 | 43 | print("Hex-rays version %s has been detected" % ida_hexrays.get_hexrays_version()) 44 | 45 | f = ida_funcs.get_func(ida_kernwin.get_screen_ea()) 46 | if f is None: 47 | print("Please position the cursor within a function") 48 | return True 49 | 50 | cfunc = ida_hexrays.decompile(f); 51 | if cfunc is None: 52 | print("Failed to decompile!") 53 | return True 54 | 55 | print_pseudo_code(cfunc) 56 | 57 | lst = find_calls(cfunc) 58 | lst = list(set(lst)) 59 | already = [] 60 | for ea in lst: 61 | f = ida_funcs.get_func(ea) 62 | if f is None: 63 | continue 64 | 65 | cfunc = ida_hexrays.decompile(f); 66 | if cfunc is None: 67 | print("Failed to decompile!") 68 | return True 69 | print_pseudo_code(cfunc) 70 | 71 | return True 72 | 73 | if __name__ == '__main__': 74 | main() -------------------------------------------------------------------------------- /api-examples/idb/frame_event_listener.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: log various frame events. 3 | 4 | description: 5 | hooks to be notified about frame IDP events, and 6 | dump their information to the "Output" window. 7 | """ 8 | import inspect 9 | import ida_idp 10 | import ida_ua 11 | 12 | class frame_logger_hooks_t(ida_idp.IDB_Hooks): 13 | def __init__(self): 14 | ida_idp.IDB_Hooks.__init__(self) 15 | self.inhibit_log = 0 16 | 17 | def _format_value(self, v): 18 | return str(v) 19 | 20 | def _log(self, msg=None): 21 | if self.inhibit_log <= 0: 22 | if msg: 23 | print(f'>>> frame_logger_hooks_f: {msg}') 24 | else: 25 | stack = inspect.stack() 26 | frame, _, _, _, _, _ = stack[1] 27 | args, _, _, values = inspect.getargvalues(frame) 28 | method_name = inspect.getframeinfo(frame)[2] 29 | argstrs = [] 30 | for arg in args[1:]: 31 | argstrs.append("%s=%s" % (arg, self._format_value(values[arg]))) 32 | print(f'>>> frame_logger_hooks_t.{method_name}: {", ".join(args)}') 33 | return 0 34 | 35 | def frame_udm_created(self, func_ea, udm): 36 | return self._log() 37 | 38 | def frame_udm_deleted(self, func_ea, udm_tid, udm): 39 | return self._log() 40 | 41 | def frame_udm_renamed(self, func_ea, udm, oldname): 42 | return self._log() 43 | 44 | def frame_udm_changed(self, func_ea, udm_tid, udmold, udmnew): 45 | return self._log() 46 | 47 | 48 | 49 | # Remove an existing hook on second run 50 | try: 51 | frame_idp_hook_stat = "un" 52 | print("Frame IDP hook: checking for hook...") 53 | framehook 54 | print("Frame IDP hook: unhooking....") 55 | frame_idp_hook_stat2 = "" 56 | framehook.unhook() 57 | del framehook 58 | except: 59 | print("Frame IDP hook: not installed, installing now....") 60 | frame_idp_hook_stat = "" 61 | frame_idp_hook_stat2 = "un" 62 | framehook = frame_logger_hooks_t() 63 | framehook.hook() 64 | 65 | print(f'Frame IDB hook {frame_idp_hook_stat}installed. Run the script again to {frame_idp_hook_stat2}install') -------------------------------------------------------------------------------- /api-examples/inf/print_basic_info_plugin.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Python plugin that print basic IDB information. 3 | 4 | description: 5 | Demonstrates how to turn an IDA python script into 6 | an IDA Python plugin. 7 | """ 8 | import ida_idaapi 9 | import ida_kernwin 10 | import print_basic_info 11 | 12 | class pbi_plugmod_t(ida_idaapi.plugmod_t): 13 | def __del__(self): 14 | ida_kernwin.msg("PBI >> unloaded pbi_plugmod\n") 15 | 16 | def run(self, arg): 17 | ida_kernwin.msg("PBI >> run() called with %d!\n" % arg) 18 | print_basic_info.main() 19 | return True 20 | 21 | class pbi_plugin_t(ida_idaapi.plugin_t): 22 | flags = ida_idaapi.PLUGIN_UNL | ida_idaapi.PLUGIN_MULTI 23 | comment = "This is a simple plugin printing basic info" 24 | help = "" 25 | wanted_name = "Print Basic Info (PBI) plugin" 26 | wanted_hotkey = "Ctrl-Alt-F12" 27 | 28 | 29 | def init(self): 30 | ida_kernwin.msg("PBI >> init() called!\n") 31 | return pbi_plugmod_t() 32 | 33 | def term(self): 34 | ida_kernwin.msg("PBI >> ERROR: term() called (should never be called)\n") 35 | 36 | def PLUGIN_ENTRY(): 37 | return pbi_plugin_t() -------------------------------------------------------------------------------- /api-examples/readme.md: -------------------------------------------------------------------------------- 1 | # TIL API examples: 2 | 3 | ## Beginner level examples: 4 | * list_enum_member.py 5 | * list_struct_member.py 6 | * list_union_member.py 7 | * import_type_from_til.py 8 | * list_struct_xref.py 9 | * create_array.py 10 | 11 | ## Intermediate level examples: 12 | * create_structs.py 13 | * create_libssh2.py 14 | * create_bmenum.py 15 | * create_bfstruct.py 16 | * func_ti_changed_listener.py 17 | * mark_func_spoiled.py 18 | * setpehdr.py 19 | 20 | ## Advanced level examples: 21 | * operand_to_struct_member.py 22 | -------------------------------------------------------------------------------- /api-examples/segm/list_imports.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: List the .idata section content and the corresponding 3 | data and code references when it applies. 4 | 5 | description: 6 | In this script, we iterate through the .idata PE section. 7 | For each imported function we display: 8 | * its name 9 | * the data references to it (when applying) 10 | * the code references to it (when applying, 11 | """ 12 | import ida_segment 13 | import ida_name 14 | import idautils 15 | import ida_kernwin 16 | import ida_funcs 17 | 18 | def is_code(ea): 19 | return ida_segment.segtype(ea) == ida_segment.SEG_CODE 20 | 21 | def newline(): 22 | print('') 23 | 24 | def list_refs(refs, code): 25 | first = True 26 | if code: 27 | type = 'code' 28 | else: 29 | type = 'data' 30 | 31 | idx = 1 32 | for ref in refs: 33 | if first: 34 | print(f'\tList of {type} references:') 35 | first = False 36 | ida_kernwin.msg(f'\t* [{idx}] @ {ref:x}') 37 | if is_code(ref): 38 | name = ida_funcs.get_func_name(ref) 39 | if name: 40 | print(f' ({name})') 41 | else: 42 | newline() 43 | else: 44 | newline() 45 | idx += 1 46 | 47 | 48 | def main(): 49 | import_seg = ida_segment.get_segm_by_name('.idata') 50 | 51 | if import_seg: 52 | curr_ea = import_seg.start_ea 53 | end_ea = import_seg.end_ea 54 | idx = 1 55 | while curr_ea < end_ea: 56 | name = ida_name.get_ea_name(curr_ea) 57 | print(f'Imported function [{idx}]: {name}') 58 | 59 | list_refs(idautils.DataRefsTo(curr_ea), False) 60 | 61 | list_refs(idautils.CodeRefsTo(curr_ea, 0), True) 62 | 63 | if import_seg.is_64bit(): 64 | curr_ea += 8 65 | else: 66 | curr_ea += 4 67 | idx += 1 68 | 69 | 70 | if __name__ == '__main__': 71 | main() -------------------------------------------------------------------------------- /api-examples/typeinf/add_frame_member.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Programatically ad a new frame member to an existing frame. 3 | 4 | description: 5 | This script goal is to demonstrate some usage of the type API. 6 | In this script, we demonstrate a way to ad a new frame member 7 | inside a wide enough gap in the frame: 8 | * Get the function object surrounding cursor location. 9 | * Use this function to retrieve the corresponding frame object. 10 | * Find a wide enough gap to create our new member. 11 | * If found, we use cal_frame_offset() to get the actual 12 | offset in the frame structure. 13 | * Use the previous result to add the new member. 14 | """ 15 | import ida_funcs 16 | import ida_frame 17 | import ida_typeinf 18 | import ida_range 19 | 20 | name = 'my_stkvar' 21 | sp_offset = 0 22 | 23 | tif = ida_typeinf.tinfo_t(ida_typeinf.BTF_UINT64) 24 | tif.create_ptr(tif) 25 | 26 | func = ida_funcs.get_func(here()) 27 | if func: 28 | print(f'Function @ {func.start_ea:x}') 29 | frame_tif = ida_typeinf.tinfo_t() 30 | if ida_frame.get_func_frame(frame_tif, func): 31 | print(f'{frame_tif._print()}') 32 | rs = ida_range.rangeset_t() 33 | if frame_tif.calc_gaps(rs): 34 | for range in rs: 35 | if range.start_ea <= 0: 36 | continue 37 | elif (range.end_ea - range.start_ea) >= tif.get_size(): 38 | sp_offset = range.start_ea 39 | print(f'Range [{range.start_ea:x}, {range.end_ea:x}[ selected.') 40 | break 41 | if sp_offset: 42 | sval = ida_frame.calc_frame_offset(func, sp_offset, None, None) 43 | if ida_frame.add_frame_member(func, name, sval, tif): 44 | print('Success!') 45 | else: 46 | print('Failure :(') 47 | -------------------------------------------------------------------------------- /api-examples/typeinf/apply_callee_tinfo.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Programatically apply locally created function type info 3 | to all the addresses refering to that function. 4 | 5 | description: 6 | This script goal is to demonstrate some usage of the type API. 7 | In this script, we: 8 | * Open the private type libary. 9 | * Load its declaration in the type library by parsing its declaration and 10 | keep the return tuple for future use. 11 | * Deserialize the type info stored in the returned tuple. 12 | * Get the address of the function. 13 | * Get the address of the code reference to the function and apply 14 | the type info there. 15 | """ 16 | import ida_typeinf 17 | import ida_name 18 | import idautils 19 | import ida_idaapi 20 | 21 | til = ida_typeinf.get_idati() 22 | tuple = ida_typeinf.idc_parse_decl(til, 'NTSTATUS __fastcall KdInitSystem(ULONG BootPhase, _LOADER_PARAMETER_BLOCK *LoaderBlock);', ida_typeinf.PT_REPLACE) 23 | if not tuple == None: 24 | tif = ida_typeinf.tinfo_t() 25 | if tif.deserialize(til, tuple[1], tuple[2]): 26 | ea = ida_name.get_name_ea(ida_idaapi.BADADDR, 'KdInitSystem') 27 | if not ea == ida_idaapi.BADADDR: 28 | print(f'KdIniSystem function found @ {ea:x}.') 29 | for xref in idautils.CodeRefsTo(ea, 0): 30 | print(f'\tApplying type info @ {xref:x}.') 31 | ida_typeinf.apply_callee_tinfo(xref, tif) 32 | -------------------------------------------------------------------------------- /api-examples/typeinf/change_stkvar_name.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Programatically change the name of an *existing* stack variable. 3 | 4 | description: 5 | This script goal is to demonstrate some usage of the type API. 6 | In this script, we demonstrate a way to change the name of a 7 | stack variable: 8 | * Get the function object surrounding cursor location. 9 | * Use this function to retrieve the corresponding frame object. 10 | * Find the frame member matching the given name. 11 | * Using its offset in the frame structure object, calculate 12 | the actual stack delta. 13 | * Use the previous result to redefine the stack variable name if 14 | it is not a special or argument member. 15 | """ 16 | import ida_funcs 17 | import ida_frame 18 | import ida_typeinf 19 | 20 | old_name = 'arg_8' 21 | new_name = 'Renamed' 22 | 23 | func = ida_funcs.get_func(here()) 24 | if func: 25 | print(f'Function @ {func.start_ea:x}') 26 | frame_tif = ida_typeinf.tinfo_t() 27 | if ida_frame.get_func_frame(frame_tif, func): 28 | print(f'{frame_tif._print()}') 29 | idx = frame_tif.find_udm(old_name) 30 | if idx >= 0: 31 | print(f'Udm of {old_name} index: {idx}') 32 | udm = ida_typeinf.udm_t() 33 | tid = frame_tif.get_udm_tid(idx) 34 | if ida_frame.is_special_frame_member(tid): 35 | print(f'{old_name} is a special frame member. Will not change the name.') 36 | else: 37 | frame_tif.get_udm_by_tid(udm, tid) 38 | offset = udm.offset // 8 39 | if ida_frame.is_funcarg_off(func, offset): 40 | print(f'{old_name} is an argument member. Will not change the name.') 41 | else: 42 | sval = ida_frame.soff_to_fpoff(func, offset) 43 | print(f'Frame offset: {sval:x}') 44 | ida_frame.define_stkvar(func, new_name, sval, udm.type) 45 | else: 46 | print(f'{old_name} not found.') 47 | else: 48 | print('No frame returned.') 49 | else: 50 | print('Please position the cursor inside a function.') -------------------------------------------------------------------------------- /api-examples/typeinf/create_array.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Programatically create an array. 3 | 4 | description: 5 | This script goal is to demonstrate some usage of the type API. 6 | In this script, we create an array using both versions of 7 | create_array tinfo_t method. 8 | """ 9 | 10 | import ida_typeinf 11 | 12 | """ 13 | Delete the types if they already exist. 14 | """ 15 | tif = ida_typeinf.tinfo_t() 16 | if tif.get_named_type(None, 'my_int_array1'): 17 | ida_typeinf.del_named_type(None, 'my_int_array1', ida_typeinf.NTF_TYPE) 18 | 19 | tif = ida_typeinf.tinfo_t() 20 | if tif.get_named_type(None, 'my_int_array2'): 21 | ida_typeinf.del_named_type(None, 'my_int_array2', ida_typeinf.NTF_TYPE) 22 | 23 | """ 24 | First method: 25 | * Create the type info object of the array element. 26 | * Create an array of 5 integers (base index set to zero) 27 | """ 28 | tif = ida_typeinf.tinfo_t(ida_typeinf.BTF_INT) 29 | if tif.create_array(tif, 5, 0): 30 | type = tif._print() 31 | print(f'{type}') 32 | tif.set_named_type(None, 'my_int_array1') 33 | 34 | """ 35 | Second method: 36 | * Create an array type data object representing an array 37 | of 5 integers with base index 0. 38 | * Create the array using the just constructed object. 39 | """ 40 | atd = ida_typeinf.array_type_data_t() 41 | atd.base = 0 42 | atd.nelems = 5 43 | atd.elem_type = ida_typeinf.tinfo_t(ida_typeinf.BTF_INT) 44 | tif = ida_typeinf.tinfo_t() 45 | if tif.create_array(atd): 46 | type = tif._print() 47 | print(f'{type}') 48 | tif.set_named_type(None, 'my_int_array2') 49 | -------------------------------------------------------------------------------- /api-examples/typeinf/create_bfstruct.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Programatically create a bitfield structure. 3 | 4 | description: 5 | This script goal is to demonstrate some usage of the type API. 6 | In this script, we: 7 | * Create a bitfield structure. In the present case the bitfield is an int32 8 | made of three 'members' spanning it entirely: 9 | bit0->bit19: bf1 10 | bit20->bit25: bf2 11 | bit26->bit31: bf3 12 | * For each member create a repeatable comment. 13 | """ 14 | import ida_typeinf 15 | 16 | # Create a bitfield structure. 17 | tif = ida_typeinf.tinfo_t() 18 | if tif.get_named_type(None, 'bfstruct'): 19 | ida_typeinf.del_named_type(None, 'bfstruct', ida_typeinf.NTF_TYPE) 20 | 21 | udt = ida_typeinf.udt_type_data_t() 22 | idx = 0 23 | for name, offset, size, bitfield_info in [ 24 | ("bf1", 0, 20, (4, 20)), 25 | ("bf2", 20, 6, (4, 6)), 26 | ("bf3", 26, 6, (4, 6)) 27 | ]: 28 | udm = ida_typeinf.udm_t() 29 | udm.name = name 30 | bftif = ida_typeinf.tinfo_t() 31 | bf_bucket_size, bf_nbits = bitfield_info 32 | bftif.create_bitfield(bf_bucket_size, bf_nbits) 33 | udm.type = bftif 34 | udm.offset = offset 35 | udm.size = size 36 | udm.cmt = f'Bitfield member {idx}' 37 | udt.push_back(udm) 38 | if tif.create_udt(udt): 39 | tif.set_named_type(None, 'bfstruct') -------------------------------------------------------------------------------- /api-examples/typeinf/create_bmenum.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Programatically create a bitmask enum. 3 | 4 | description: 5 | This script goal is to demonstrate some usage of the type API. 6 | In this script, we: 7 | * Create a bitmask enumeration member by member. 8 | * Flags the enumeration as a bitmask one. 9 | """ 10 | import ida_typeinf 11 | 12 | tif = ida_typeinf.tinfo_t() 13 | edt = ida_typeinf.enum_type_data_t() 14 | edm = ida_typeinf.edm_t() 15 | edm.name = 'field1' 16 | edm.value = 1 17 | edt.push_back(edm) 18 | edm.name = 'field2' 19 | edm.value = 2 20 | edt.push_back(edm) 21 | edm.name = 'field3' 22 | edm.value = 4 23 | edt.push_back(edm) 24 | if tif.create_enum(edt): 25 | tif.set_enum_is_bitmask(ida_typeinf.tinfo_t.ENUMBM_ON) 26 | tif.set_named_type(None, 'bmenum') 27 | -------------------------------------------------------------------------------- /api-examples/typeinf/create_libssh2_til.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Programatically create a til file. 3 | 4 | description: 5 | This script goal is to demonstrate some usage of the type API. 6 | In this script, we: 7 | * We create a new libssh2-64.til file where we load some libssh2 8 | 64-bit structures. 9 | * Once the file has been created, it can copied in the IDA install 10 | til directory or in the user IDA til directory. 11 | """ 12 | import ida_typeinf 13 | import ida_kernwin 14 | 15 | libssh2_types = """ 16 | typedef unsigned char uint8_t; 17 | typedef unsigned int uint32_t; 18 | typedef __int64 size_t; 19 | 20 | struct _LIBSSH2_USERAUTH_KBDINT_PROMPT 21 | { 22 | unsigned char *text; 23 | size_t length; 24 | unsigned char echo; 25 | }; 26 | typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT LIBSSH2_USERAUTH_KBDINT_PROMPT; 27 | 28 | struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE 29 | { 30 | char *text; 31 | unsigned int length; 32 | }; 33 | typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE LIBSSH2_USERAUTH_KBDINT_RESPONSE; 34 | 35 | struct _LIBSSH2_SK_SIG_INFO { 36 | uint8_t flags; 37 | uint32_t counter; 38 | unsigned char *sig_r; 39 | size_t sig_r_len; 40 | unsigned char *sig_s; 41 | size_t sig_s_len; 42 | }; 43 | typedef struct _LIBSSH2_SK_SIG_INFO LIBSSH2_SK_SIG_INFO; 44 | 45 | """ 46 | 47 | 48 | def add_types(): 49 | # Create a new til file. 50 | t = ida_typeinf.new_til("libssh2-64.til", "Few libssh2 types") 51 | # Parse the declaratiion, ignoring redeclaration warnings and applying default packing/ 52 | if ida_typeinf.parse_decls(t, libssh2_types, None, ida_typeinf.HTI_DCL | ida_typeinf.HTI_PAKDEF): 53 | ida_kernwin.msg('Failed to parse the libssh2 declarations.\n') 54 | return 55 | ida_typeinf.compact_til(t) 56 | # The til file will be saved in the current working directory. 57 | if ida_typeinf.store_til(t, None, "libssh2-64.til"): 58 | ida_kernwin.msg("TIL file stored on disk.\n") 59 | ida_typeinf.free_til(t) 60 | 61 | if __name__ == "__main__": 62 | add_types() 63 | -------------------------------------------------------------------------------- /api-examples/typeinf/create_user_shared_data.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Programatically create a segment hodling the user 3 | shared data area in ntdll.dll. 4 | 5 | description: 6 | This script goal is to demonstrate some usage of the type API. 7 | In this script, we show how to create, set type and name of 8 | a user shared data region in an ntdll IDB: 9 | * Get _KUSER_SHARED_DATA type info. 10 | * Create a data segment with UserSharedData as its name. 11 | * Apply the type to the start of the newly created segment base 12 | address. 13 | * Set the address name. 14 | """ 15 | import ida_segment 16 | import ida_typeinf 17 | import ida_name 18 | import ida_kernwin 19 | 20 | USE64 = 2 21 | PERM_RW = 0x6 22 | start_ea = 0x7FFE0000 23 | type_name = '_KUSER_SHARED_DATA' 24 | 25 | tif = ida_typeinf.tinfo_t() 26 | if tif.get_named_type(None, type_name, ida_typeinf.BTF_STRUCT): 27 | segm = ida_segment.segment_t() 28 | segm.start_ea = start_ea 29 | segm.end_ea = start_ea + tif.get_size() 30 | segm.sel = ida_segment.setup_selector(0) 31 | segm.bitness = USE64 32 | segm.align = ida_segment.saRelPara 33 | segm.comb = ida_segment.scPub 34 | segm.perm = PERM_RW 35 | if ida_segment.add_segm_ex(segm, 'UserSharedData', 'DATA', 0) < 0: 36 | ida_kernwin.msg('Unable to create the shared data segment.\n') 37 | else: 38 | if not ida_typeinf.apply_tinfo(start_ea, tif, ida_typeinf.TINFO_DEFINITE): 39 | ida_kernwin.msg(f'Unable to apply type information @ {start_ea:x}.\n') 40 | else: 41 | if ida_name.set_name(start_ea, 'UserSharedData'): 42 | ida_kernwin.msg('Done!') 43 | else: 44 | ida_kernwin.msg(f'Unable to set {start_ea:x} name.\n') 45 | else: 46 | ida_kernwin.msg(f'Unable to import {type_name}') 47 | -------------------------------------------------------------------------------- /api-examples/typeinf/del_struct_members.py: -------------------------------------------------------------------------------- 1 | import ida_typeinf 2 | 3 | def del_struct_members(sid, offset1, offset2): 4 | tif = ida_typeinf.tinfo_t() 5 | if tif.get_type_by_tid(sid) and tif.is_udt(): 6 | udm = ida_typeinf.udm_t() 7 | udm.offset = offset1 * 8 8 | idx1 = tif.find_udm(udm, ida_typeinf.STRMEM_OFFSET) 9 | udm = ida_typeinf.udm_t() 10 | udm.offset = offset2 * 8 11 | idx2 = tif.find_udm(udm, ida_typeinf.STRMEM_OFFSET) 12 | return tif.del_udms(idx1, idx2) 13 | 14 | def get_best_fit_member(sid, offset): 15 | tif = ida_typeinf.tinfo_t() 16 | if tif.get_type_by_tid(sid) and tif.is_udt(): 17 | udt = ida_typeinf.udt_type_data_t() 18 | if tif.get_udt_details(udt): 19 | return udt.get_best_fit_member(offset) 20 | 21 | def get_innermost_member(sid, offset): 22 | tif = ida_typeinf.tinfo_t() 23 | if tif.get_type_by_tid(sid) and tif.is_udt(): 24 | (mtif, idx, _) = tif.get_innermost_udm(offset * 8) 25 | udt = ida_typeinf.udt_type_data_t() 26 | if not idx == -1: 27 | if tif.get_udt_details(udt): 28 | return mtif, udt[idx] 29 | return None 30 | 31 | struct_str = """struct pcap_hdr_s { 32 | uint32_t magic_number; /* magic number */ 33 | uint16_t version_major; /* major version number */ 34 | uint16_t version_minor; /* minor version number */ 35 | int32_t thiszone; /* GMT to local correction */ 36 | uint32_t sigfigs; /* accuracy of timestamps */ 37 | uint32_t snaplen; /* max length of captured packets, in octets */ 38 | uint32_t network; /* data link type */ 39 | };""" 40 | tif = ida_typeinf.tinfo_t() 41 | if tif.get_named_type(None, 'pcap_hdr_s'): 42 | ida_typeinf.del_named_type(None, 'pcap_hdr_s', ida_typeinf.NTF_TYPE) 43 | ida_typeinf.idc_parse_types(struct_str, 0) 44 | if not tif.get_named_type(None, 'pcap_hdr_s'): 45 | print('Unable to retrieve pcap_hdr_s structure') 46 | -------------------------------------------------------------------------------- /api-examples/typeinf/func_ti_changed_listener.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Display information about function type information changes. 3 | 4 | description: 5 | This script goal is to demonstrate some usage of the type API. 6 | In this script, we: 7 | * Create an IDB hook that intercept ti_changed IDB event. 8 | - We deserialize the type data to reconstruct the tinfo_t 9 | object 10 | - We check it is a function and print details if it is the 11 | case 12 | """ 13 | import ida_funcs 14 | import ida_idp 15 | import ida_typeinf 16 | 17 | class ti_changed_t(ida_idp.IDB_Hooks): 18 | 19 | def __del__(self): 20 | self.unhook() 21 | 22 | 23 | def print_details(self, tif, ea): 24 | if tif.is_func(): 25 | func_name = ida_funcs.get_func_name(ea) 26 | print(f'\t{tif._print(func_name)}') 27 | 28 | 29 | def ti_changed(self, ea, types, fields): 30 | tif = ida_typeinf.tinfo_t() 31 | tif.deserialize(None, types, fields) 32 | if tif.is_func(): 33 | print(f'Function type information changed @ {ea:x}') 34 | self.print_details(tif, ea) 35 | 36 | 37 | try: 38 | my_hook_stat = "un" 39 | my_hook_stat2 = "" 40 | print("IDB hook: Checking for hook...") 41 | idbhook 42 | print("IDB hook: unhooking...") 43 | del idbhook 44 | except: 45 | print("IDB hook: not installed, installing now...") 46 | my_hook_stat = "" 47 | my_hook_stat2 = "un" 48 | idbhook = ti_changed_t() 49 | idbhook.hook() 50 | 51 | print(f'IDB hook {my_hook_stat}installed. Run the script again to {my_hook_stat2}install') -------------------------------------------------------------------------------- /api-examples/typeinf/gap_size_align_snippet.py: -------------------------------------------------------------------------------- 1 | import ida_typeinf 2 | import ida_range 3 | 4 | # Get size of struct member + alignment 5 | def get_member_size_align(struct_name, member_off): 6 | tif = ida_typeinf.tinfo_t() 7 | if tif.get_named_type(None, struct_name): 8 | udm = ida_typeinf.udm_t() 9 | udm.offset = member_off * 8 10 | if not tif.find_udm(udm, ida_typeinf.STRMEM_OFFSET) == -1: 11 | return udm.type.get_size(), udm.effalign 12 | return -1, -1 13 | 14 | ## Check if offset is part of a gap 15 | 16 | def is_struct_gap(struc_name, offset): 17 | tif = ida_typeinf.tinfo_t() 18 | if not tif.get_named_type(None, struc_name): 19 | return False 20 | rs = ida_range.rangeset_t() 21 | tif.calc_gaps(rs) 22 | for i in range(rs.nranges()): 23 | r = rs.getrange(i) 24 | if r.start_ea <= offset < r.end_ea: 25 | return True 26 | 27 | print(struc_name, hex(offset)) 28 | return False -------------------------------------------------------------------------------- /api-examples/typeinf/import_type_from_til.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Progarmatically load a til and a type. 3 | 4 | description: 5 | This script goal is to demonstrate some usage of the type API. 6 | In this script, we: 7 | * ask the user for a specific til to be lodaed 8 | * if successfully loaded ask the user for a type name to be imported. 9 | * append the type to the local types. 10 | """ 11 | import ida_netnode 12 | import ida_typeinf 13 | import ida_kernwin 14 | 15 | til_name = ida_kernwin.ask_str('Dummy til name', 0, 'Enter a til filename:') 16 | if til_name: 17 | ret = ida_typeinf.add_til(til_name, ida_typeinf.ADDTIL_DEFAULT) 18 | if ret == ida_typeinf.TIL_ADD_OK or ret == ida_typeinf.TIL_ADD_ALREADY: 19 | til = ida_typeinf.get_idati() 20 | type_name = ida_kernwin.ask_str('Dummy type name', 0, 'Enter a type name') 21 | if type_name: 22 | tid = ida_netnode.BADNODE 23 | tif = ida_typeinf.tinfo_t() 24 | if tif.get_named_type(None, type_name): 25 | tid = tif.force_tid() 26 | if tid == ida_netnode.BADNODE: 27 | print(f'{type_name} type import failed.') 28 | else: 29 | print(f'{type_name} type has been imported.') 30 | else: 31 | print(f'No type name provided.') 32 | else: 33 | print(f'{til_name} not added.') 34 | -------------------------------------------------------------------------------- /api-examples/typeinf/list_enum_member.py: -------------------------------------------------------------------------------- 1 | import ida_kernwin 2 | import ida_typeinf 3 | 4 | name = ida_kernwin.ask_str('Dummy enum', 0, 'Enter an enum name:') 5 | if name: 6 | til = ida_typeinf.get_idati() 7 | tif = ida_typeinf.tinfo_t() 8 | if not tif.get_named_type(til, name, ida_typeinf.BTF_ENUM, True, False): 9 | print(f"'{name}' is not an enum") 10 | elif tif.is_typedef(): 11 | print(f"'{name}' is not a (non typedefed) enum.") 12 | else: 13 | edt = ida_typeinf.enum_type_data_t() 14 | if tif.get_enum_details(edt): 15 | idx = 0 16 | bitfield = '' 17 | if edt.is_bf(): 18 | bitfield = '(bitfield)' 19 | print(f"Listing the '{name}' {bitfield} enum {edt.size()} field names:") 20 | for edm in edt: 21 | print(f'Field {idx}: {edm.name} = {edm.value}') 22 | idx += 1 23 | else: 24 | print(f"Unable to get udt details for enum '{name}'") 25 | -------------------------------------------------------------------------------- /api-examples/typeinf/list_frame_info.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Programatically list some frame information. 3 | 4 | description: 5 | This script goal is to demonstrate some usage of the type API. 6 | In this script, we: 7 | * Get the function object surrounding the cursor location. 8 | * Get the corresponding frame object. 9 | * Get the details about the frame. 10 | * Iterate them and display their: 11 | - Index 12 | - Name 13 | - Offset (starting and ending in bytes) 14 | - Type 15 | """ 16 | import ida_funcs 17 | import ida_frame 18 | import ida_typeinf 19 | 20 | func = ida_funcs.get_func(here()) 21 | if func: 22 | func_name = ida_funcs.get_func_name(func.start_ea) 23 | frame_tif = ida_typeinf.tinfo_t() 24 | if ida_frame.get_func_frame(frame_tif, func): 25 | frame_udt = ida_typeinf.udt_type_data_t() 26 | if frame_tif.get_udt_details(frame_udt): 27 | print('List frame information:') 28 | print('-----------------------') 29 | print(f'{func_name} @ {func.start_ea:x} framesize {frame_tif.get_size():x}') 30 | print(f'Local variable size: {func.frsize:x}') 31 | print(f'Saved registers: {func.frregs:x}') 32 | print(f'Argument size: {func.argsize:x}') 33 | print('{') 34 | idx = 0 35 | for udm in frame_udt: 36 | print(f'\t[{idx}] {udm.name}: soff={udm.offset//8:x} eof={udm.end()//8:x} {udm.type.dstr()}') 37 | idx += 1 38 | print('}') 39 | else: 40 | print(f'{here():x} is not inside a function.') 41 | -------------------------------------------------------------------------------- /api-examples/typeinf/list_func_details.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Programatically displays information about functions types. 3 | 4 | description: 5 | This script goal is to demonstrate some usage of the type API. 6 | In this script, we demonstrate how to list a function return type 7 | allong with its parameters types and name if any. We do this for 8 | all the functions found in the database. 9 | """ 10 | import ida_funcs 11 | import ida_typeinf 12 | import ida_kernwin 13 | import ida_nalt 14 | import idautils 15 | 16 | ida_kernwin.msg_clear() 17 | func_qty = ida_funcs.get_func_qty() 18 | print(f'Listing {func_qty} functions') 19 | for _, ea in enumerate(idautils.Functions()): 20 | tif = ida_typeinf.tinfo_t() 21 | if not ida_nalt.get_tinfo(tif, ea): 22 | print(f'Function @ {ea:x} has no type.') 23 | continue 24 | if tif.is_func(): 25 | print(f'Function @ {ea:x} return type: {tif.get_rettype()}') 26 | funcdata = ida_typeinf.func_type_data_t() 27 | tif.get_func_details(funcdata) 28 | for pos, argument in enumerate(funcdata): 29 | print(f'\targument {pos + 1}: {argument.type} {argument.name}') -------------------------------------------------------------------------------- /api-examples/typeinf/list_stkvar_xrefs.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Programatically list the xref for each stack variables 3 | in the frame. 4 | 5 | description: 6 | This script goal is to demonstrate some usage of the type API. 7 | In this script, we demonstrate how to list each stack variables 8 | xref: 9 | * Get the function object surrounding cursor location. 10 | * Use this function to retrieve the corresponding frame object. 11 | * For each frame element: 12 | - Build the stack variable xref list 13 | - Print it. 14 | """ 15 | import ida_typeinf 16 | import ida_frame 17 | import ida_funcs 18 | import ida_xref 19 | 20 | func = ida_funcs.get_func(here()) 21 | if func: 22 | print(f'Function @ {func.start_ea:x}') 23 | 24 | frame_tif = ida_typeinf.tinfo_t() 25 | if ida_frame.get_func_frame(frame_tif, func): 26 | print('Frame found') 27 | nmembers = frame_tif.get_udt_nmembers() 28 | print(f'Frame has {nmembers} members') 29 | 30 | if nmembers > 0: 31 | frame_udt = ida_typeinf.udt_type_data_t() 32 | if frame_tif.get_udt_details(frame_udt): 33 | 34 | for frame_udm in frame_udt: 35 | start_off = frame_udm.begin() // 8 36 | end_off = frame_udm.end() // 8 37 | xreflist = ida_frame.xreflist_t() 38 | ida_frame.build_stkvar_xrefs(xreflist, func, start_off, end_off) 39 | size = xreflist.size() 40 | print(f'{frame_udm.name} stack variable starts @ {start_off:x}, ends @ {end_off:x}, xref size: {size}') 41 | 42 | for idx in range(size): 43 | match xreflist[idx].type: 44 | case ida_xref.dr_R: 45 | type = 'READ' 46 | case ida_xref.dr_W: 47 | type = 'WRITE' 48 | case _: 49 | type = 'UNK' 50 | print(f'\t[{idx}]: xref @ {xreflist[idx].ea:x} of type {type}') 51 | else: 52 | print('Unable to get the frame details.') 53 | else: 54 | print('No members found.') 55 | else: 56 | print('No function under the cursor') 57 | -------------------------------------------------------------------------------- /api-examples/typeinf/list_struct_member.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Programatically list the members of a user provided structure name. 3 | 4 | description: 5 | This script goal is to demonstrate some usage of the type API. 6 | In this script, we: 7 | * Ask the user for a structure name. It must already be present in the 8 | local types. 9 | * Retrieve the structure type info from the local type 10 | * Extract its type details (udt) 11 | * Iterates it members and prints their names. 12 | """ 13 | 14 | import ida_kernwin 15 | import ida_typeinf 16 | 17 | name = ida_kernwin.ask_str('Dummy struct', 0, 'Enter a structure name:') 18 | if name: 19 | til = ida_typeinf.get_idati() 20 | tif = ida_typeinf.tinfo_t() 21 | if not tif.get_named_type(til, name, ida_typeinf.BTF_STRUCT, True, False): 22 | print(f"'{name}' is not a structure") 23 | elif tif.is_typedef(): 24 | print(f"'{name}' is not a (non typedefed) structure.") 25 | else: 26 | udt = ida_typeinf.udt_type_data_t() 27 | if tif.get_udt_details(udt): 28 | idx = 0 29 | print(f'Listing the {name} structure {udt.size()} field names:') 30 | for udm in udt: 31 | print(f'Field {idx}: {udm.name}') 32 | idx += 1 33 | else: 34 | print(f"Unable to get udt details for structure '{name}'") 35 | 36 | -------------------------------------------------------------------------------- /api-examples/typeinf/list_struct_xrefs.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Programatically list the addresses where a particular structure 3 | is referenced. 4 | 5 | description: 6 | This script goal is to demonstrate some usage of the type API. 7 | In this script, we: 8 | * Ask the user for a structure name. It must already be present in the 9 | local types. 10 | * Get its tid 11 | * Create the list of all the reference. 12 | * Print it 13 | """ 14 | import ida_kernwin 15 | import ida_typeinf 16 | import ida_xref 17 | import ida_pro 18 | 19 | tif = ida_typeinf.tinfo_t() 20 | ref_eas = [] 21 | if ida_kernwin.choose_struct(tif, 'Choose one structure:'): 22 | tid = tif.get_tid() 23 | xrefblk = ida_xref.xrefblk_t() 24 | for ea in xrefblk.drefs_to(tid): 25 | ref_eas.append(ea) 26 | 27 | if not len(ref_eas): 28 | print('No reference found.') 29 | else: 30 | idx = 1 31 | for ea in ref_eas: 32 | print(f'Refnum {idx}: {ea:x}') -------------------------------------------------------------------------------- /api-examples/typeinf/list_union_member.py: -------------------------------------------------------------------------------- 1 | import ida_kernwin 2 | import ida_typeinf 3 | 4 | name = ida_kernwin.ask_str('Dummy union', 0, 'Enter a union name:') 5 | if name: 6 | til = ida_typeinf.get_idati() 7 | tif = ida_typeinf.tinfo_t() 8 | if not tif.get_named_type(til, name, ida_typeinf.BTF_UNION, True, False): 9 | print(f"'{name}' is not a union") 10 | elif tif.is_typedef(): 11 | print(f"'{name}' is not a (non typedefed) union.") 12 | else: 13 | udt = ida_typeinf.udt_type_data_t() 14 | if tif.get_udt_details(udt): 15 | idx = 0 16 | print(f'Listing the {name} union {udt.size()} field names:') 17 | for udm in udt: 18 | print(f'Field {idx}: {udm.name}') 19 | idx += 1 20 | else: 21 | print(f"Unable to get udt details for union '{name}'") 22 | -------------------------------------------------------------------------------- /api-examples/typeinf/mark_func_spoiled.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Programmatically change the signature of a function to __spoils 3 | 4 | description: 5 | The script goal is to demonstrate some usage of the type API. 6 | At least two possibilies are offered in order to indicate that a function 7 | spoils registers (excluding the "normal" ones): 8 | * by parsing a declaration (we assume that the func object has already been created): 9 | func_tfinfo = ida_typeinf.tinfo_t() 10 | func_tinfo.parse('int _spoils main();') 11 | ida_typeinf.apply_tinfo(func.start_ea, func_tinfo, ida_typeinf.TINFO_DEFINITE) 12 | * by editing the tinfo_t object spoiled registers vector and flags. This script uses 13 | this method. 14 | 15 | """ 16 | 17 | import ida_funcs 18 | import ida_typeinf 19 | import ida_idp 20 | import ida_kernwin 21 | import ida_nalt 22 | 23 | regs = ["rsi"] 24 | 25 | func = ida_funcs.get_func(ida_kernwin.get_screen_ea()) 26 | func_type = ida_typeinf.tinfo_t() 27 | ida_nalt.get_tinfo(func_type, func.start_ea) 28 | func_details = ida_typeinf.func_type_data_t() 29 | func_type.get_func_details(func_details) 30 | for reg in regs: 31 | reg_info = ida_idp.reg_info_t() 32 | ida_idp.parse_reg_name(reg_info, reg) 33 | func_details.spoiled.push_back(reg_info) 34 | func_details.flags |= ida_typeinf.FTI_SPOILED 35 | func_type.create_func(func_details) 36 | ida_typeinf.apply_tinfo(func.start_ea, func_type, ida_typeinf.TINFO_DEFINITE) 37 | -------------------------------------------------------------------------------- /api-examples/typeinf/visit_tinfo.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: Programatically visit a type. 3 | 4 | description: 5 | This script goal is to demonstrate some usage of the type API. 6 | In this script, we show an example of tinfo_visitor_t to list 7 | a user define type members. In case of an array or a pointer we 8 | do not visit the child by calling prune_now() visitor member 9 | method. 10 | """ 11 | import ida_typeinf 12 | import ida_netnode 13 | import idc 14 | 15 | class tinfo_visitor(ida_typeinf.tinfo_visitor_t): 16 | 17 | def __init__(self): 18 | ida_typeinf.tinfo_visitor_t.__init__(self, ida_typeinf.TVST_DEF) 19 | 20 | def visit_type(self, out, tif, name, cmt): 21 | type_name = tif.get_type_name() 22 | if tif.is_udt(): 23 | print(f'visited udt: {type_name} {name}') 24 | elif tif.is_array(): 25 | ai = ida_typeinf.array_type_data_t() 26 | if tif.get_array_details(ai): 27 | type_name = ai.elem_type._print() 28 | nelems = ai.nelems 29 | print(f'visited array: {type_name} {name}[{nelems}]') 30 | self.prune_now() 31 | elif tif.is_scalar(): 32 | print(f'visited scalar: {type_name} {name}') 33 | elif tif.is_ptr(): 34 | print(f'visited pointer: {type_name} {name}') 35 | self.prune_now() 36 | else: 37 | print(f'visited unknown: {type_name} {name}') 38 | 39 | return 0 40 | 41 | ida_typeinf.add_til('mssdk64_win10', ida_typeinf.ADDTIL_DEFAULT) 42 | til = ida_typeinf.get_idati() 43 | 44 | idh_id = idc.import_type(-1, '_IMAGE_DOS_HEADER') 45 | if idh_id != ida_netnode.BADNODE: 46 | tif = ida_typeinf.tinfo_t() 47 | if tif.get_named_type(None, '_IMAGE_DOS_HEADER'): 48 | tinfo_visitor().apply_to(tif) 49 | else: 50 | print('Unable to get _IMAGE_DOS_HEADER type info.') 51 | else: 52 | print('Import of _IMAGE_DOS_HEADER failed.') -------------------------------------------------------------------------------- /copy_docs_to_p4.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | #ensure out folder exists 6 | mkdir -p $3 7 | 8 | IN_FOLDER=$(realpath $2) 9 | OUT_FOLDER=$(realpath $3) 10 | 11 | ARTIFACTS=$1 12 | 13 | echo "[${ARTIFACTS}] GOING to COPY FILES from ${IN_FOLDER} to ${OUT_FOLDER}" 14 | 15 | cd ${OUT_FOLDER} 16 | 17 | echo "[${ARTIFACTS}] make the out folder p4 edit" 18 | p4 edit ... 19 | 20 | echo "[${ARTIFACTS}] copy new files" 21 | rm -rf * 22 | cp -R ${IN_FOLDER}/* . 23 | 24 | echo "[${ARTIFACTS}] adding files to p4" 25 | p4 add ... 26 | p4 revert -a ... 27 | 28 | -------------------------------------------------------------------------------- /docs/notes.txt: -------------------------------------------------------------------------------- 1 | Assorted notes 2 | -------------- 3 | 4 | Wrapped functions and constants: 5 | 6 | All the symbols from the idaapi module are listed in symbollist.txt. 7 | Documentation for the plugin API functions functions is in the IDA 8 | SDK header files. All function and symbol names directly translate 9 | to the C++ counterparts. If you try to use a function that is not 10 | wrapped yet you will get an exception like this: 11 | 12 | Traceback (most recent call last): 13 | File "", line 1, in ? 14 | NameError: name 'foobar' is not defined 15 | 16 | If this happens you can check the function in symbollist.txt. If it 17 | is not included and it should be please report it to the author. 18 | 19 | 20 | Data types: 21 | 22 | All the C++ data types are mapped to corresponding Python data types. 23 | For example ea_t maps to a Python integer. Complex data types (like 24 | structures and classes) are mapped to Python classes that have the 25 | same attributes as the original type. 26 | 27 | 28 | Arguments and return values: 29 | 30 | Generally all function arguments should be the same type as specified 31 | by the original headers. Pointers to complex types (structures, classes) 32 | are checked and must match the original declarations. 33 | 34 | For example comment = get_func_comment("aa", 0) will raise an exception: 35 | 36 | Traceback (most recent call last): 37 | File "", line 1, in ? 38 | TypeError: Type error. Got aa, expected _p_func_t 39 | 40 | When calling functions that return a string in a buffer (usually with 41 | maximum size) the buffer and size parameter is omitted. These functions 42 | return either the result in a string or None if the call fails and returns 43 | NULL. The output buffers are maximized at MAXSTR. 44 | 45 | Example: 46 | 47 | C++: get_func_name(0x1234, buf, sizeof(buf)); 48 | Python: name = get_func_name(0x1234) 49 | 50 | Any function that should return a char * is going to return either a 51 | Python string (up to MAXSTR) or None. 52 | 53 | 54 | -------------------------------------------------------------------------------- /docs/pydoc.md: -------------------------------------------------------------------------------- 1 | 2 | # IDAPython runtime documentation 3 | 4 | We define the "IDAPython runtime documentation" as the documentation 5 | that's available through Python's `help()` system, while the user is 6 | interacting with `IDAPython` during an IDA session. 7 | 8 | That documentation is SWiG-generated + patched, or custom written. 9 | 10 | ## Custom-written documentation 11 | 12 | Some functions have custom-written documentation (check for 13 | tags in the `pywraps/` directory), but the general case is that the 14 | documentation is automatically generated by SWiG, and then patched. 15 | 16 | ## SWiG-generated + patched documentation 17 | 18 | Because SWiG doesn't know about the C++ SDK header's documentation, we 19 | need a way to "import" that documentation into IDAPython. 20 | 21 | That's done by `tools/inject_pydoc.py` which deserves 22 | [its own documentation](inject_pydoc.md) 23 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | 2 | # IDAPython examples 3 | 4 | This directory contains a variety of examples demonstrating 5 | how IDA can be scripted using IDAPython. 6 | 7 | ## Adding a new example (for Hex-Rays developers) 8 | 9 | When adding an example, the author (i.e., a Hex-Rays developer) 10 | must add a corresponding test, making sure the example is properly 11 | tested, and doesn't regress over time (see `idapython-examples`, 12 | and `idapython_hr-examples` test suites.) This has the added benefit 13 | that this ensures our APIs remain stable. 14 | 15 | Also, any significant addition to IDAPython APIs should come 16 | with one or many examples, and those should be also put under test 17 | (in other words: it's better if a test relies on a real example, 18 | rather than if it consists of a bunch of IDAPython code our 19 | users will never see, and cannot be inspired from.) 20 | 21 | ### Best practices 22 | 23 | * don't use `idc.py`: some of its operations are a bit too elusive 24 | * don't use `idaapi`: that "hides" the provenance of the 25 | function/type/item being used, and makes it that much harder to 26 | group ideas by module 27 | * don't `from import `: for the same reason 28 | 29 | ## Helping our customers, teaching IDAPython in the process 30 | 31 | In addition, when a customer asks for help on support@ (or the forums) 32 | and we end up sending a significant body of IDAPython code as a reply, 33 | since that body of code should be tested anyway, it's better to make 34 | a real example out of it ... and, of course, put that example under 35 | test as well. 36 | 37 | ## Maintaining quality 38 | 39 | There should be no such thing as a non-tested example. 40 | 41 | ## Updating the examples index 42 | 43 | All examples are automatically integrated in the examples index. 44 | In order to show user-friendly & relevant information, a proper 45 | header (docstring) needs to be present. 46 | -------------------------------------------------------------------------------- /examples/core/add_hotkey.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: triggering bits of code by pressing a shortcut 3 | 4 | description: 5 | `ida_kernwin.add_hotkey` is a simpler, but much less flexible 6 | alternative to `ida_kernwin.register_action` (though it does 7 | use the same mechanism under the hood.) 8 | 9 | It's particularly useful during prototyping, but note that the 10 | actions that are created cannot be inserted in menus, toolbars 11 | or cannot provide a custom `ida_kernwin.action_handler_t.update` 12 | callback. 13 | 14 | keywords: actions 15 | 16 | see_also: actions 17 | """ 18 | 19 | import ida_kernwin 20 | 21 | def hotkey_pressed(): 22 | print("hotkey pressed!") 23 | 24 | try: 25 | hotkey_ctx 26 | if ida_kernwin.del_hotkey(hotkey_ctx): 27 | print("Hotkey unregistered!") 28 | del hotkey_ctx 29 | else: 30 | print("Failed to delete hotkey!") 31 | except: 32 | hotkey_ctx = ida_kernwin.add_hotkey("Shift-A", hotkey_pressed) 33 | if hotkey_ctx is None: 34 | print("Failed to register hotkey!") 35 | del hotkey_ctx 36 | else: 37 | print("Hotkey registered!") 38 | -------------------------------------------------------------------------------- /examples/core/add_idc_hotkey.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: triggering bits of code by pressing a shortcut (older version) 3 | 4 | description: 5 | This is a somewhat ancient way of registering actions & binding 6 | shortcuts. It's still here for reference, but "fresher" alternatives 7 | should be preferred. 8 | 9 | keywords: actions 10 | 11 | see_also: actions, add_hotkey 12 | """ 13 | 14 | import ida_expr 15 | import ida_kernwin 16 | 17 | def say_hi(): 18 | print("Hotkey activated!") 19 | 20 | # IDA binds hotkeys to IDC functions so a trampoline IDC function must be created 21 | ida_expr.compile_idc_text('static key_2() { RunPythonStatement("say_hi()"); }') 22 | 23 | # Add the hotkey 24 | ida_kernwin.add_idc_hotkey("2", 'key_2') 25 | 26 | # Press 2 to activate foo() 27 | 28 | # The hotkey can be removed with 29 | # ida_kernwin.del_idc_hotkey('2') 30 | 31 | -------------------------------------------------------------------------------- /examples/core/colorize_disassembly.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: change background colours 3 | 4 | description: 5 | This illustrates the setting/retrieval of background colours 6 | using the IDC wrappers 7 | 8 | In order to do so, we'll be assigning colors to specific ranges 9 | (item, function, or segment). Those will be persisted in the 10 | database. 11 | 12 | category: disassembly 13 | 14 | keywords: coloring, idc 15 | 16 | see_also: colorize_disassembly_on_the_fly 17 | """ 18 | 19 | BG_BLUE = 0xc02020 20 | BG_GREEN = 0x208020 21 | BG_RED = 0x2020c0 22 | 23 | import idc 24 | 25 | ea = idc.here() 26 | idc.set_color(ea, idc.CIC_SEGM, BG_BLUE) 27 | idc.set_color(ea, idc.CIC_FUNC, BG_GREEN) 28 | idc.set_color(ea, idc.CIC_ITEM, BG_RED) 29 | print("Segment: %x" % idc.get_color(ea, idc.CIC_SEGM)) 30 | print("Function: %x" % idc.get_color(ea, idc.CIC_FUNC)) 31 | print("Item: %x" % idc.get_color(ea, idc.CIC_ITEM)) 32 | -------------------------------------------------------------------------------- /examples/core/dump_flowchart.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | summary: dump function flowchart 4 | 5 | description: 6 | Dumps the current function's flowchart, using 2 methods: 7 | 8 | * the low-level `ida_gdl.qflow_chart_t` type 9 | * the somewhat higher-level, and slightly more pythonic 10 | `ida_gdl.FlowChart` type. 11 | """ 12 | 13 | import ida_gdl 14 | import ida_funcs 15 | import ida_kernwin 16 | 17 | def out(p, msg): 18 | if p: 19 | print(msg) 20 | 21 | def out_succ(p, start_ea, end_ea): 22 | out(p, " SUCC: %x - %x" % (start_ea, end_ea)) 23 | 24 | def out_pred(p, start_ea, end_ea): 25 | out(p, " PRED: %x - %x" % (start_ea, end_ea)) 26 | 27 | 28 | # ----------------------------------------------------------------------- 29 | # Using ida_gdl.qflow_chart_t 30 | def using_qflow_chart_t(ea, p=True): 31 | f = ida_funcs.get_func(ea) 32 | if not f: 33 | return 34 | 35 | q = ida_gdl.qflow_chart_t("The title", f, 0, 0, 0) 36 | for n in range(q.size()): 37 | b = q[n] 38 | out(p, "%x - %x [%d]:" % (b.start_ea, b.end_ea, n)) 39 | for ns in range(q.nsucc(n)): 40 | b2 = q[q.succ(n, ns)] 41 | out_succ(p, b2.start_ea, b2.end_ea) 42 | 43 | for ns in range(q.npred(n)): 44 | b2 = q[q.pred(n, ns)] 45 | out_pred(p, b2.start_ea, b2.end_ea) 46 | 47 | # ----------------------------------------------------------------------- 48 | # Using ida_gdl.FlowChart 49 | def using_FlowChart(ea, p=True): 50 | f = ida_gdl.FlowChart(ida_funcs.get_func(ea)) 51 | 52 | for block in f: 53 | out(p, "%x - %x [%d]:" % (block.start_ea, block.end_ea, block.id)) 54 | for succ_block in block.succs(): 55 | out_succ(p, succ_block.start_ea, succ_block.end_ea) 56 | 57 | for pred_block in block.preds(): 58 | out_pred(p, pred_block.start_ea, pred_block.end_ea) 59 | 60 | ea = ida_kernwin.get_screen_ea() 61 | 62 | print(">>> Dumping flow chart using ida_gdl.qflow_chart_t") 63 | using_qflow_chart_t(ea) 64 | 65 | print(">>> Dumping flow chart using the higher-level ida_gdl.FlowChart") 66 | using_FlowChart(ea) 67 | 68 | -------------------------------------------------------------------------------- /examples/core/extend_idc.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: add functions to the IDC runtime from IDAPython 3 | 4 | description: 5 | You can add IDC functions to IDA, whose "body" consists of 6 | IDAPython statements! 7 | 8 | We'll register a 'pow' function, available to all IDC code, 9 | that when invoked will call back into IDAPython, and execute 10 | the provided function body. 11 | 12 | After running this script, try switching to the IDC interpreter 13 | (using the button on the lower-left corner of IDA) and executing 14 | `pow(3, 7)` 15 | """ 16 | 17 | import ida_expr 18 | 19 | if ida_expr.add_idc_func( 20 | "pow", 21 | lambda n, e: n ** e, 22 | (ida_expr.VT_LONG, ida_expr.VT_LONG)): 23 | print("The pow() function is now available in IDC") 24 | else: 25 | print("Failed to register pow() IDC function") 26 | -------------------------------------------------------------------------------- /examples/core/idapythonrc.py: -------------------------------------------------------------------------------- 1 | r""" 2 | summary: code to be run right after IDAPython initialization 3 | 4 | description: 5 | The `idapythonrc.py` file: 6 | 7 | * %APPDATA%\Hex-Rays\IDA Pro\idapythonrc.py (on Windows) 8 | * ~/.idapro/idapythonrc.py (on Linux & Mac) 9 | 10 | can contain any IDAPython code that will be run as soon as 11 | IDAPython is done successfully initializing. 12 | """ 13 | 14 | # Add your favourite script to ScriptBox for easy access 15 | # scriptbox.addscript("/here/is/my/favourite/script.py") 16 | 17 | # Uncomment if you want to set Python as default interpreter in IDA 18 | # import ida_idaapi 19 | # ida_idaapi.enable_extlang_python(True) 20 | 21 | # Disable the Python from interactive command-line 22 | # import ida_idaapi 23 | # ida_idaapi.enable_python_cli(False) 24 | 25 | # Set the timeout for the script execution cancel dialog 26 | # import ida_idaapi 27 | # ida_idaapi.set_script_timeout(10) 28 | -------------------------------------------------------------------------------- /examples/core/install_user_defined_prefix.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: inserting information into disassembly prefixes 3 | 4 | description: 5 | By default, disassembly line prefixes contain segment + address 6 | information (e.g., '.text:08047718'), but it is possible to 7 | "inject" other bits of information in there, thanks to the 8 | `ida_lines.user_defined_prefix_t` helper type. 9 | """ 10 | 11 | import ida_lines 12 | import ida_idaapi 13 | 14 | PREFIX = ida_lines.SCOLOR_INV + ' ' + ida_lines.SCOLOR_INV 15 | 16 | class my_user_prefix_t(ida_lines.user_defined_prefix_t): 17 | def get_user_defined_prefix(self, ea, insn, lnnum, indent, line): 18 | if (ea % 2 == 0) and indent == -1: 19 | return PREFIX 20 | else: 21 | return "" 22 | 23 | 24 | class prefix_plugin_t(ida_idaapi.plugin_t): 25 | flags = 0 26 | comment = "This is a user defined prefix sample plugin" 27 | help = "This is help" 28 | wanted_name = "user defined prefix" 29 | wanted_hotkey = "" 30 | 31 | def __init__(self): 32 | self.prefix = None 33 | 34 | def init(self): 35 | self.prefix = my_user_prefix_t(8) 36 | print("prefix installed") 37 | return ida_idaapi.PLUGIN_KEEP 38 | 39 | def run(self, arg): 40 | pass 41 | 42 | def term(self): 43 | self.prefix = None 44 | print("prefix uninstalled!") 45 | 46 | 47 | def PLUGIN_ENTRY(): 48 | return prefix_plugin_t() 49 | 50 | -------------------------------------------------------------------------------- /examples/core/list_bookmarks.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: list bookmarks associated to a listing 3 | 4 | description: 5 | This sample shows how to programmatically access the list of 6 | bookmarks placed in a listing widget (e.g., "IDA View-A", 7 | "Pseudocode-", …) using the low-level `ida_moves.bookmarks_t` 8 | type. 9 | 10 | keywords: bookmarks 11 | """ 12 | 13 | import ida_kernwin 14 | import ida_moves 15 | 16 | class list_bookmarks_ah_t(ida_kernwin.action_handler_t): 17 | def activate(self, ctx): 18 | v = ida_kernwin.get_current_viewer() 19 | if v: 20 | print("### Bookmarks for %s" % ida_kernwin.get_widget_title(v)) 21 | ud = ida_kernwin.get_viewer_user_data(v) 22 | for loc, desc in ida_moves.bookmarks_t(v): 23 | print("\t'%s': %s" % (loc.place()._print(ud), desc)) 24 | 25 | def update(self, ctx): 26 | return ida_kernwin.AST_ENABLE_FOR_WIDGET \ 27 | if ida_kernwin.get_current_viewer() \ 28 | else ida_kernwin.AST_DISABLE_FOR_WIDGET 29 | 30 | ACTION_NAME = "example:list_bookmarks" 31 | ACTION_LABEL = "List bookmarks" 32 | ACTION_SHORTCUT = "Ctrl+!" 33 | ACTION_HELP = "Press %s to list bookmarks" % ACTION_SHORTCUT 34 | 35 | if ida_kernwin.register_action(ida_kernwin.action_desc_t( 36 | ACTION_NAME, 37 | ACTION_LABEL, 38 | list_bookmarks_ah_t(), 39 | ACTION_SHORTCUT)): 40 | print("Registered action \"%s\". %s" % (ACTION_LABEL, ACTION_HELP)) 41 | -------------------------------------------------------------------------------- /examples/core/list_imports.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: enumerate file imports 3 | 4 | description: 5 | Using the API to enumerate file imports. 6 | """ 7 | 8 | import ida_nalt 9 | 10 | nimps = ida_nalt.get_import_module_qty() 11 | 12 | print("Found %d import(s)..." % nimps) 13 | 14 | for i in range(nimps): 15 | name = ida_nalt.get_import_module_name(i) 16 | if not name: 17 | print("Failed to get import module name for #%d" % i) 18 | name = "" 19 | 20 | print("Walking imports for module %s" % name) 21 | def imp_cb(ea, name, ordinal): 22 | if not name: 23 | print("%08x: ordinal #%d" % (ea, ordinal)) 24 | else: 25 | print("%08x: %s (ordinal #%d)" % (ea, name, ordinal)) 26 | # True -> Continue enumeration 27 | # False -> Stop enumeration 28 | return True 29 | ida_nalt.enum_import_names(i, imp_cb) 30 | 31 | print("All done...") 32 | -------------------------------------------------------------------------------- /examples/core/list_patched_bytes.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: enumerate patched bytes 3 | 4 | description: 5 | Using the API to iterate over all the places in the file, 6 | that were patched using IDA. 7 | """ 8 | 9 | import ida_bytes 10 | import ida_idaapi 11 | 12 | # ------------------------------------------------------------------------- 13 | class patched_bytes_visitor(object): 14 | def __init__(self): 15 | self.skip = 0 16 | self.patch = 0 17 | 18 | def __call__(self, ea, fpos, o, v, cnt=()): 19 | if fpos == -1: 20 | self.skip += 1 21 | print(" ea: %x o: %x v: %x...skipped" % (ea, o, v)) 22 | else: 23 | self.patch += 1 24 | print(" ea: %x fpos: %x o: %x v: %x" % (ea, fpos, o, v)) 25 | return 0 26 | 27 | 28 | # ------------------------------------------------------------------------- 29 | def main(): 30 | print("Visiting all patched bytes:") 31 | v = patched_bytes_visitor() 32 | r = ida_bytes.visit_patched_bytes(0, ida_idaapi.BADADDR, v) 33 | if r != 0: 34 | print("visit_patched_bytes() returned %d" % r) 35 | else: 36 | print("Patched: %d Skipped: %d" % (v.patch, v.skip)) 37 | 38 | 39 | # ------------------------------------------------------------------------- 40 | if __name__ == '__main__': 41 | main() 42 | -------------------------------------------------------------------------------- /examples/core/list_problems.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: enumerate problems 3 | 4 | description: 5 | Using the API to list all problem[atic situation]s that IDA 6 | encountered during analysis. 7 | """ 8 | 9 | import ida_ida 10 | import ida_idaapi 11 | import ida_problems 12 | 13 | for ptype in [ 14 | ida_problems.PR_NOBASE, 15 | ida_problems.PR_NONAME, 16 | ida_problems.PR_NOFOP, 17 | ida_problems.PR_NOCMT, 18 | ida_problems.PR_NOXREFS, 19 | ida_problems.PR_JUMP, 20 | ida_problems.PR_DISASM, 21 | ida_problems.PR_HEAD, 22 | ida_problems.PR_ILLADDR, 23 | ida_problems.PR_MANYLINES, 24 | ida_problems.PR_BADSTACK, 25 | ida_problems.PR_ATTN, 26 | ida_problems.PR_FINAL, 27 | ida_problems.PR_ROLLED, 28 | ida_problems.PR_COLLISION, 29 | ida_problems.PR_DECIMP, 30 | ]: 31 | plistdesc = ida_problems.get_problem_name(ptype) 32 | ea = ida_ida.inf_get_min_ea() 33 | while True: 34 | ea = ida_problems.get_problem(ptype, ea+1) 35 | if ea == ida_idaapi.BADADDR: 36 | break 37 | print("0x%08x: %s" % (ea, plistdesc)) 38 | -------------------------------------------------------------------------------- /examples/core/list_segment_functions.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: list all functions (and xrefs) in segment 3 | 4 | description: 5 | List all the functions in the current segment, as well as 6 | all the cross-references to them. 7 | 8 | keywords: xrefs 9 | 10 | see_also: list_segment_functions_using_idautils 11 | """ 12 | 13 | # 14 | # Reference Lister 15 | # 16 | # List all functions and all references to them in the current section. 17 | # 18 | # Implemented using direct IDA Plugin API calls 19 | # 20 | 21 | import ida_kernwin 22 | import ida_segment 23 | import ida_funcs 24 | import ida_xref 25 | import ida_idaapi 26 | 27 | def main(): 28 | # Get current ea 29 | ea = ida_kernwin.get_screen_ea() 30 | 31 | # Get segment class 32 | seg = ida_segment.getseg(ea) 33 | 34 | # Loop from segment start to end 35 | func_ea = seg.start_ea 36 | 37 | # Get a function at the start of the segment (if any) 38 | func = ida_funcs.get_func(func_ea) 39 | if func is None: 40 | # No function there, try to get the next one 41 | func = ida_funcs.get_next_func(func_ea) 42 | 43 | seg_end = seg.end_ea 44 | while func is not None and func.start_ea < seg_end: 45 | funcea = func.start_ea 46 | print("Function %s at 0x%x" % (ida_funcs.get_func_name(funcea), funcea)) 47 | 48 | xb = ida_xref.xrefblk_t() 49 | for ref in xb.crefs_to(funcea): 50 | print(" called from %s(0x%x)" % (ida_funcs.get_func_name(ref), ref)) 51 | 52 | func = ida_funcs.get_next_func(funcea) 53 | 54 | 55 | main() 56 | -------------------------------------------------------------------------------- /examples/core/list_segment_functions_using_idautils.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: list all functions (and xrefs) in segment 3 | 4 | description: 5 | List all the functions in the current segment, as well as 6 | all the cross-references to them. 7 | 8 | Contrary to @list_segment_functions, this uses the somewhat 9 | higher-level `idautils` module. 10 | 11 | keywords: xrefs 12 | 13 | see_also: list_segment_functions 14 | """ 15 | 16 | # 17 | # Reference Lister 18 | # 19 | # List all functions and all references to them in the current section. 20 | # 21 | # Implemented with the idautils module 22 | # 23 | 24 | import ida_kernwin 25 | import ida_idaapi 26 | import ida_segment 27 | import ida_funcs 28 | 29 | import idautils 30 | 31 | def main(): 32 | # Get current ea 33 | ea = ida_kernwin.get_screen_ea() 34 | if ea == ida_idaapi.BADADDR: 35 | print("Could not get get_screen_ea()") 36 | return 37 | 38 | seg = ida_segment.getseg(ea) 39 | if seg: 40 | # Loop from start to end in the current segment 41 | for funcea in idautils.Functions(seg.start_ea, seg.end_ea): 42 | print("Function %s at 0x%x" % (ida_funcs.get_func_name(funcea), funcea)) 43 | 44 | # Find all code references to funcea 45 | for ref in idautils.CodeRefsTo(funcea, 1): 46 | print(" called from %s(0x%x)" % (ida_funcs.get_func_name(ref), ref)) 47 | else: 48 | print("Please position the cursor within a segment") 49 | 50 | if __name__=='__main__': 51 | main() 52 | -------------------------------------------------------------------------------- /examples/core/list_strings.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: retrieve the strings that are present in the IDB 3 | 4 | description: 5 | This uses `idautils.Strings` to iterate over the string literals 6 | that are present in the IDB. Contrary to @show_selected_strings, 7 | this will not require that the "Strings" window is opened & available. 8 | 9 | see_also: show_selected_strings 10 | """ 11 | 12 | import ida_nalt 13 | import idautils 14 | 15 | s = idautils.Strings(False) 16 | s.setup(strtypes=[ida_nalt.STRTYPE_C, ida_nalt.STRTYPE_C_16]) 17 | for i, v in enumerate(s): 18 | if v is None: 19 | print("Failed to retrieve string index %d" % i) 20 | else: 21 | print("%x: len=%d type=0x%x index=%d-> '%s'" % (v.ea, v.length, v.strtype, i, str(v))) 22 | -------------------------------------------------------------------------------- /examples/core/produce_c_file.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: decompile entire file 3 | 4 | description: 5 | automate IDA to perform auto-analysis on a file and, 6 | once that is done, produce a .c file containing the 7 | decompilation of all the functions in that file. 8 | 9 | Run like so: 10 | 11 | ida -A "-S...path/to/produce_c_file.py" 12 | 13 | where: 14 | 15 | * -A instructs IDA to run in non-interactive mode 16 | * -S holds a path to the script to run (note this is a single token; 17 | there is no space between '-S' and its path.) 18 | """ 19 | 20 | import ida_pro 21 | import ida_auto 22 | import ida_loader 23 | import ida_hexrays 24 | 25 | # derive output file name 26 | idb_path = ida_loader.get_path(ida_loader.PATH_TYPE_IDB) 27 | c_path = "%s.c" % idb_path 28 | 29 | ida_auto.auto_wait() # wait for end of auto-analysis 30 | ida_hexrays.decompile_many( # generate .c file 31 | c_path, 32 | None, 33 | ida_hexrays.VDRUN_NEWFILE 34 | |ida_hexrays.VDRUN_SILENT 35 | |ida_hexrays.VDRUN_MAYSTOP) 36 | 37 | ida_pro.qexit(0) 38 | -------------------------------------------------------------------------------- /examples/core/produce_lst_file.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: produce listing 3 | 4 | description: 5 | automate IDA to perform auto-analysis on a file and, 6 | once that is done, produce a .lst file with the disassembly. 7 | 8 | Run like so: 9 | 10 | ida -A "-S...path/to/produce_lst_file.py" 11 | 12 | where: 13 | 14 | * -A instructs IDA to run in non-interactive mode 15 | * -S holds a path to the script to run (note this is a single token; 16 | there is no space between '-S' and its path.) 17 | """ 18 | 19 | import ida_auto 20 | import ida_fpro 21 | import ida_ida 22 | import ida_loader 23 | import ida_pro 24 | 25 | # derive output file name 26 | idb_path = ida_loader.get_path(ida_loader.PATH_TYPE_IDB) 27 | lst_path = "%s.lst" % idb_path 28 | 29 | ida_auto.auto_wait() # wait for end of auto-analysis 30 | fptr = ida_fpro.qfile_t() # FILE * wrapper 31 | if fptr.open(lst_path, "wt"): 32 | try: 33 | ida_loader.gen_file( # generate .lst file 34 | ida_loader.OFILE_LST, 35 | fptr.get_fp(), 36 | ida_ida.inf_get_min_ea(), 37 | ida_ida.inf_get_max_ea(), 38 | 0) 39 | finally: 40 | fptr.close() 41 | 42 | ida_pro.qexit(0) 43 | -------------------------------------------------------------------------------- /examples/core/register_timer.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: using timers for delayed execution 3 | 4 | description: 5 | Register (possibly repeating) timers. 6 | """ 7 | 8 | import ida_kernwin 9 | 10 | # ------------------------------------------------------------------------- 11 | class timercallback_t(object): 12 | def __init__(self): 13 | self.interval = 1000 14 | self.obj = ida_kernwin.register_timer(self.interval, self) 15 | if self.obj is None: 16 | raise RuntimeError("Failed to register timer") 17 | self.times = 5 18 | 19 | def __call__(self): 20 | print("Timer invoked. %d time(s) left" % self.times) 21 | self.times -= 1 22 | # Unregister the timer when the counter reaches zero 23 | return -1 if self.times == 0 else self.interval 24 | 25 | def __del__(self): 26 | print("Timer object disposed %s" % self) 27 | 28 | 29 | # ------------------------------------------------------------------------- 30 | def main(): 31 | try: 32 | t = timercallback_t() 33 | # No need to unregister the timer. 34 | # It will unregister itself in the callback when it returns -1 35 | except Exception as e: 36 | print("Error: %s" % e) 37 | 38 | 39 | # ------------------------------------------------------------------------- 40 | if __name__ == '__main__': 41 | main() 42 | -------------------------------------------------------------------------------- /examples/debugging/appcall/simple_appcall_common.py: -------------------------------------------------------------------------------- 1 | 2 | import ida_dbg 3 | import ida_idaapi 4 | import ida_idd 5 | import ida_kernwin 6 | import ida_typeinf 7 | import ida_name 8 | 9 | def log(msg): 10 | print(">>> %s" % msg) 11 | 12 | class appcall_hooks_t(ida_dbg.DBG_Hooks): 13 | def __init__(self, name_funcs=[]): 14 | ida_dbg.DBG_Hooks.__init__(self) # important 15 | 16 | for ea, func_name in name_funcs: 17 | log("Renaming 0x%08x to \"%s\"" % (ea, func_name)) 18 | ida_name.set_name(ea, func_name) 19 | 20 | for func_name, func_proto in [ 21 | ("ref4", "int ref4(int *);"), 22 | ("ref8", "int ref8(long long int *);"), 23 | ]: 24 | log("Setting '%s's prototype" % func_name) 25 | func_ea = ida_name.get_name_ea(ida_idaapi.BADADDR, func_name) 26 | assert(ida_typeinf.apply_cdecl(None, func_ea, func_proto)) 27 | 28 | 29 | def dbg_run_to(self, pid, tid, ea): 30 | log("'run_to' reached its target location. Performing appcalls.") 31 | 32 | for func_name in ["ref4", "ref8"]: 33 | int_value = ida_idd.Appcall.int64(5) 34 | int_ptr = ida_idd.Appcall.byref(int_value) 35 | if ida_idd.Appcall[func_name](int_ptr): 36 | log("Appcall (%s) succeeded: int_value.value=%s, int_ptr.value=%s" % ( 37 | func_name, 38 | int_value.value, 39 | int_ptr.value)) 40 | else: 41 | log("Appcall (%s) failed" % func_name) 42 | 43 | 44 | def run(self): 45 | log("Running program up to current address, and letting the hooks do the rest") 46 | assert(ida_dbg.run_to(ida_kernwin.get_screen_ea())) 47 | -------------------------------------------------------------------------------- /examples/debugging/appcall/simple_appcall_linux.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: executing code into the application being debugged (on Linux) 3 | 4 | description: 5 | Using the `ida_idd.Appcall` utility to execute code in 6 | the process being debugged. 7 | 8 | This example will run the test program and stop wherever 9 | the cursor currently is, and then perform an appcall to 10 | execute the `ref4` and `ref8` functions. 11 | 12 | To use this example: 13 | 14 | * run `ida64` on test program `simple_appcall_linux64`, or 15 | `ida` on test program `simple_appcall_linux32`, and wait for 16 | auto-analysis to finish 17 | * select the 'linux debugger' (either local, or remote) 18 | * run this script 19 | 20 | Note: the real body of code is in `simple_appcall_common.py`. 21 | """ 22 | 23 | import os 24 | import sys 25 | sys.path.append(os.path.dirname(__file__)) 26 | 27 | import simple_appcall_common 28 | appcall_hooks = simple_appcall_common.appcall_hooks_t() 29 | appcall_hooks.hook() 30 | appcall_hooks.run() 31 | -------------------------------------------------------------------------------- /examples/debugging/appcall/simple_appcall_win.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: executing code into the application being debugged (on Windows) 3 | 4 | description: 5 | Using the `ida_idd.Appcall` utility to execute code in 6 | the process being debugged. 7 | 8 | This example will run the test program and stop wherever 9 | the cursor currently is, and then perform an appcall to 10 | execute the `ref4` and `ref8` functions. 11 | 12 | To use this example: 13 | 14 | * run `ida64` on test program `simple_appcall_win64.exe`, or 15 | `ida` on test program `simple_appcall_win32.exe`, and wait for 16 | auto-analysis to finish 17 | * select the 'windows debugger' (either local, or remote) 18 | * run this script 19 | 20 | Note: the real body of code is in `simple_appcall_common.py`. 21 | """ 22 | 23 | import os 24 | import sys 25 | sys.path.append(os.path.dirname(__file__)) 26 | 27 | # Windows binaries don't have any symbols, thus we'll have 28 | # to assign names to addresses of interest before we can 29 | # appcall them by name. 30 | import ida_ida 31 | if ida_ida.inf_is_64bit(): 32 | ref4_ea = 0x140001000 33 | ref8_ea = 0x140001060 34 | else: 35 | ref4_ea = 0x401000 36 | ref8_ea = 0x401050 37 | 38 | import simple_appcall_common 39 | appcall_hooks = simple_appcall_common.appcall_hooks_t( 40 | name_funcs=[ 41 | (ref4_ea, "ref4"), 42 | (ref8_ea, "ref8"), 43 | ]) 44 | 45 | appcall_hooks.hook() 46 | appcall_hooks.run() 47 | -------------------------------------------------------------------------------- /examples/debugging/appcall/test_programs/simple_appcall/makefile: -------------------------------------------------------------------------------- 1 | 2 | ifdef __NT__ 3 | EA32_TARGET:=simple_appcall_win32.exe 4 | EA64_TARGET:=simple_appcall_win64.exe 5 | else 6 | ifdef __LINUX__ 7 | EA32_TARGET:=simple_appcall_linux32 8 | EA64_TARGET:=simple_appcall_linux64 9 | else 10 | $(error Not implemented for OSX) 11 | endif 12 | endif 13 | 14 | all: $(EA32_TARGET) $(EA64_TARGET) 15 | 16 | simple_appcall_win32.exe: simple_appcall_win32.obj 17 | C:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/bin/HostX86/x86/link.exe \ 18 | /LIBPATH:C:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/lib/x86 \ 19 | /LIBPATH:C:/PROGRA~2/WI3CF2~1/10/Lib/100171~1.0/ucrt/x86 \ 20 | /LIBPATH:C:/idasrc/THIRD_~1/mssdk/8.1/Lib/x86 \ 21 | /OUT:$@ $< 22 | 23 | simple_appcall_win32.obj: simple_appcall.c 24 | C:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/bin/HostX86/x86/cl.exe \ 25 | /IC:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/Include \ 26 | /IC:/PROGRA~2/WI3CF2~1/10/Include/100171~1.0/ucrt \ 27 | /Zi /D__NT__ /DNDEBUG /DWIN32 /D_CONSOLE /D__VC__ /c /MD $< /Fo$@ 28 | 29 | simple_appcall_win64.exe: simple_appcall_win64.obj 30 | C:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/bin/HostX86/x86/link.exe \ 31 | /LIBPATH:C:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/lib/x64 \ 32 | /LIBPATH:C:/PROGRA~2/WI3CF2~1/10/Lib/100171~1.0/ucrt/x64 \ 33 | /LIBPATH:C:/idasrc/THIRD_~1/mssdk/8.1/Lib/x64 \ 34 | /OUT:$@ $< 35 | 36 | simple_appcall_win64.obj: simple_appcall.c 37 | C:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/bin/HostX64/x64/cl.exe \ 38 | /IC:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/Include \ 39 | /IC:/PROGRA~2/WI3CF2~1/10/Include/100171~1.0/ucrt \ 40 | /Zi /D__NT__ /DNDEBUG /DWIN32 /D_CONSOLE /D__VC__ /c /MD $< /Fo$@ 41 | 42 | 43 | simple_appcall_linux32: simple_appcall.c 44 | gcc -m32 -o $@ $< 45 | 46 | simple_appcall_linux64: simple_appcall.c 47 | gcc -m64 -o $@ $< 48 | -------------------------------------------------------------------------------- /examples/debugging/appcall/test_programs/simple_appcall/simple_appcall.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef int int32; 4 | int ref4(int32 *a) 5 | { 6 | if (a == NULL) 7 | { 8 | printf("ref4: no number passed!"); 9 | return -1; 10 | } 11 | printf("ref4: entered with %d\n", *a); 12 | (*a)++; 13 | return 1; 14 | } 15 | 16 | typedef long long int int64; 17 | int ref8(int64 *a) 18 | { 19 | if (a == NULL) 20 | { 21 | printf("ref8: no number passed!"); 22 | return -1; 23 | } 24 | printf("ref8: entered with %lld\n", *a); 25 | (*a)++; 26 | return 1; 27 | } 28 | 29 | int main() 30 | { 31 | int32 x; 32 | int res = ref4(&x); 33 | int64 y; 34 | return res + ref8(&y); 35 | } 36 | -------------------------------------------------------------------------------- /examples/debugging/appcall/test_programs/simple_appcall/simple_appcall_linux32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HexRaysSA/IDAPython/bd1c5927f0ad44048fcd9cc42a9a743504e6c7a0/examples/debugging/appcall/test_programs/simple_appcall/simple_appcall_linux32 -------------------------------------------------------------------------------- /examples/debugging/appcall/test_programs/simple_appcall/simple_appcall_linux64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HexRaysSA/IDAPython/bd1c5927f0ad44048fcd9cc42a9a743504e6c7a0/examples/debugging/appcall/test_programs/simple_appcall/simple_appcall_linux64 -------------------------------------------------------------------------------- /examples/debugging/appcall/test_programs/simple_appcall/simple_appcall_win32.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HexRaysSA/IDAPython/bd1c5927f0ad44048fcd9cc42a9a743504e6c7a0/examples/debugging/appcall/test_programs/simple_appcall/simple_appcall_win32.exe -------------------------------------------------------------------------------- /examples/debugging/appcall/test_programs/simple_appcall/simple_appcall_win64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HexRaysSA/IDAPython/bd1c5927f0ad44048fcd9cc42a9a743504e6c7a0/examples/debugging/appcall/test_programs/simple_appcall/simple_appcall_win64.exe -------------------------------------------------------------------------------- /examples/debugging/misc/print_call_stack.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: print call stack (on Linux) 3 | 4 | description: print the return addresses from the call stack at a breakpoint. 5 | (and print also the module and the debug name from debugger) 6 | 7 | To use this example: 8 | 9 | * run `ida64` on test program `simple_appcall_linux64`, or 10 | `ida` on test program `simple_appcall_linux32`, and wait for 11 | auto-analysis to finish 12 | * put a breakpoint where you want to see the call stack 13 | * select the 'linux debugger' (either local, or remote) 14 | * start debugging 15 | * Press Shift+C at the breakpoint 16 | """ 17 | import os 18 | import ida_idaapi 19 | import ida_idd 20 | import ida_dbg 21 | import ida_kernwin 22 | import ida_name 23 | 24 | def log(msg): 25 | print(">>> %s" % msg) 26 | 27 | class print_call_stack_ah_t(): 28 | def activate(self, ctx): 29 | log("=== start of call stack impression ===") 30 | tid = ida_dbg.get_current_thread() 31 | trace = ida_idd.call_stack_t() 32 | if ida_dbg.collect_stack_trace(tid, trace): 33 | for frame in trace: 34 | mi = ida_idd.modinfo_t() 35 | if ida_dbg.get_module_info(frame.callea, mi): 36 | module = os.path.basename(mi.name) 37 | name = ida_name.get_nice_colored_name( 38 | frame.callea, 39 | ida_name.GNCN_NOCOLOR|ida_name.GNCN_NOLABEL|ida_name.GNCN_NOSEG|ida_name.GNCN_PREFDBG) 40 | log("Return address: " + hex(frame.callea) + " from: " + module + " with debug name: " + name) 41 | else: 42 | log("Return address: " + hex(frame.callea)) 43 | log("=== end of call stack impression ===") 44 | 45 | def update(self, ctx): 46 | return ida_kernwin.AST_ENABLE_ALWAYS 47 | 48 | ACTION_NAME = "example:print_call_stack" 49 | ACTION_LABEL = "Print call stack" 50 | ACTION_SHORTCUT = "Shift+C" 51 | ACTION_HELP = "Press %s to dump the call stack" % ACTION_SHORTCUT 52 | 53 | if ida_kernwin.register_action(ida_kernwin.action_desc_t( 54 | ACTION_NAME, 55 | ACTION_LABEL, 56 | print_call_stack_ah_t(), 57 | ACTION_SHORTCUT)): 58 | print("Registered action \"%s\". %s" % (ACTION_LABEL, ACTION_HELP)) 59 | 60 | -------------------------------------------------------------------------------- /examples/debugging/misc/print_registers.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: print all registers, for all threads 3 | 4 | description: iterate over the list of threads in the program being 5 | debugged, and dump all registers contents 6 | 7 | To use this example: 8 | 9 | * run `ida64` on test program `simple_appcall_linux64`, or 10 | `ida` on test program `simple_appcall_linux32`, and wait for 11 | auto-analysis to finish 12 | * put a breakpoint somewhere in the code 13 | * select the 'linux debugger' (either local, or remote) 14 | * start debugging 15 | * Press Alt+Shift+C at the breakpoint 16 | """ 17 | import ida_idd 18 | import ida_dbg 19 | 20 | def log(msg): 21 | print(">>> %s" % msg) 22 | 23 | class print_registers_ah_t(): 24 | def activate(self, ctx): 25 | log("=== registers ===") 26 | dbg = ida_idd.get_dbg() 27 | for tidx in range(ida_dbg.get_thread_qty()): 28 | tid = ida_dbg.getn_thread(tidx) 29 | log(" Thread #%d" % tid) 30 | regvals = ida_dbg.get_reg_vals(tid) 31 | for ridx, rv in enumerate(regvals): 32 | rinfo = dbg.regs(ridx) 33 | rval = rv.pyval(rinfo.dtype) 34 | if isinstance(rval, int): 35 | rval = "0x%x" % rval 36 | log(" %s: %s" % (rinfo.name, rval)) 37 | log("=== end of registers ===") 38 | 39 | def update(self, ctx): 40 | return ida_kernwin.AST_ENABLE_ALWAYS 41 | 42 | ACTION_NAME = "example:print_registers" 43 | ACTION_LABEL = "Print registers" 44 | ACTION_SHORTCUT = "Alt+Shift+C" 45 | ACTION_HELP = "Press %s to print the registers" % ACTION_SHORTCUT 46 | 47 | if ida_kernwin.register_action(ida_kernwin.action_desc_t( 48 | ACTION_NAME, 49 | ACTION_LABEL, 50 | print_registers_ah_t(), 51 | ACTION_SHORTCUT)): 52 | print("Registered action \"%s\". %s" % (ACTION_LABEL, ACTION_HELP)) 53 | 54 | -------------------------------------------------------------------------------- /examples/debugging/misc/registers_context_menu.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: adding actions to the "registers" widget(s) 3 | 4 | description: 5 | It's possible to add actions to the context menu of 6 | pretty much all widgets in IDA. 7 | 8 | This example shows how to do just that for 9 | registers-displaying widgets (e.g., "General registers") 10 | """ 11 | 12 | import ida_dbg 13 | import ida_idd 14 | import ida_kernwin 15 | import ida_ua 16 | 17 | ACTION_NAME = "registers_context_menu:dump_reg" 18 | 19 | class dump_reg_ah_t(ida_kernwin.action_handler_t): 20 | def activate(self, ctx): 21 | name = ctx.regname 22 | value = ida_dbg.get_reg_val(name) 23 | rtype = "integer" 24 | rinfo = ida_idd.register_info_t() 25 | if ida_dbg.get_dbg_reg_info(name, rinfo): 26 | if rinfo.dtype == ida_ua.dt_byte: 27 | value = "0x%02x" % value 28 | elif rinfo.dtype == ida_ua.dt_word: 29 | value = "0x%04x" % value 30 | elif rinfo.dtype == ida_ua.dt_dword: 31 | value = "0x%08x" % value 32 | elif rinfo.dtype == ida_ua.dt_qword: 33 | value = "0x%016x" % value 34 | else: 35 | rtype = "float" 36 | print("> Register %s (of type %s): %s" % (name, rtype, value)) 37 | 38 | def update(self, ctx): 39 | return ida_kernwin.AST_ENABLE_FOR_WIDGET \ 40 | if ctx.widget_type == ida_kernwin.BWN_CPUREGS \ 41 | else ida_kernwin.AST_DISABLE_FOR_WIDGET 42 | 43 | 44 | if ida_kernwin.register_action( 45 | ida_kernwin.action_desc_t( 46 | ACTION_NAME, 47 | "Dump register info", 48 | dump_reg_ah_t())): 49 | 50 | class registers_hooks_t(ida_kernwin.UI_Hooks): 51 | def finish_populating_widget_popup(self, form, popup): 52 | if ida_kernwin.get_widget_type(form) == ida_kernwin.BWN_CPUREGS: 53 | ida_kernwin.attach_action_to_popup(form, popup, ACTION_NAME) 54 | 55 | hooks = registers_hooks_t() 56 | hooks.hook() 57 | else: 58 | print("Failed to register action") 59 | -------------------------------------------------------------------------------- /examples/debugging/show_debug_names.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: retrieving & dumping debuggee symbols 3 | 4 | description: 5 | Queries the debugger (possibly remotely) for the list of 6 | symbols that the process being debugged, provides. 7 | """ 8 | 9 | import ida_dbg 10 | import ida_ida 11 | import ida_name 12 | 13 | def main(): 14 | if not ida_dbg.is_debugger_on(): 15 | print("Please run the process first!") 16 | return 17 | if ida_dbg.get_process_state() != ida_dbg.DSTATE_SUSP: 18 | print("Please suspend the debugger first!") 19 | return 20 | 21 | dn = ida_name.get_debug_names( 22 | ida_ida.inf_get_min_ea(), 23 | ida_ida.inf_get_max_ea()) 24 | for i in dn: 25 | print("%08x: %s" % (i, dn[i])) 26 | 27 | main() 28 | -------------------------------------------------------------------------------- /examples/hexrays/vds1.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: decompile & print current function. 3 | """ 4 | 5 | import ida_hexrays 6 | import ida_lines 7 | import ida_funcs 8 | import ida_kernwin 9 | 10 | def main(): 11 | if not ida_hexrays.init_hexrays_plugin(): 12 | return False 13 | 14 | print("Hex-rays version %s has been detected" % ida_hexrays.get_hexrays_version()) 15 | 16 | f = ida_funcs.get_func(ida_kernwin.get_screen_ea()); 17 | if f is None: 18 | print("Please position the cursor within a function") 19 | return True 20 | 21 | cfunc = ida_hexrays.decompile(f); 22 | if cfunc is None: 23 | print("Failed to decompile!") 24 | return True 25 | 26 | sv = cfunc.get_pseudocode(); 27 | for sline in sv: 28 | print(ida_lines.tag_remove(sline.line)); 29 | 30 | return True 31 | 32 | main() 33 | -------------------------------------------------------------------------------- /examples/hexrays/vds13.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: generates microcode for selection 3 | 4 | description: 5 | Generates microcode for selection and dumps it to the output window. 6 | """ 7 | 8 | import ida_bytes 9 | import ida_range 10 | import ida_kernwin 11 | import ida_hexrays 12 | 13 | if ida_hexrays.init_hexrays_plugin(): 14 | sel, sea, eea = ida_kernwin.read_range_selection(None) 15 | w = ida_kernwin.warning 16 | if sel: 17 | F = ida_bytes.get_flags(sea) 18 | if ida_bytes.is_code(F): 19 | hf = ida_hexrays.hexrays_failure_t() 20 | mbr = ida_hexrays.mba_ranges_t() 21 | mbr.ranges.push_back(ida_range.range_t(sea, eea)) 22 | mba = ida_hexrays.gen_microcode(mbr, hf, None, ida_hexrays.DECOMP_WARNINGS) 23 | if mba: 24 | print("Successfully generated microcode for 0x%08x..0x%08x\n" % (sea, eea)) 25 | vp = ida_hexrays.vd_printer_t() 26 | mba._print(vp) 27 | else: 28 | w("0x%08x: %s" % (hf.errea, hf.str)) 29 | else: 30 | w("The selected range must start with an instruction") 31 | else: 32 | w("Please select a range of addresses to analyze") 33 | else: 34 | print('vds13: Hex-rays is not available.') 35 | 36 | -------------------------------------------------------------------------------- /examples/hexrays/vds7.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: iterate a cblock_t object 3 | 4 | description: 5 | Using a `ida_hexrays.ctree_visitor_t`, search for 6 | `ida_hexrays.cit_block` instances and dump them. 7 | 8 | author: EiNSTeiN_ (einstein@g3nius.org) 9 | """ 10 | 11 | import ida_hexrays 12 | 13 | class cblock_visitor_t(ida_hexrays.ctree_visitor_t): 14 | 15 | def __init__(self): 16 | ida_hexrays.ctree_visitor_t.__init__(self, ida_hexrays.CV_FAST) 17 | 18 | def visit_insn(self, ins): 19 | if ins.op == ida_hexrays.cit_block: 20 | self.dump_block(ins.ea, ins.cblock) 21 | return 0 22 | 23 | def dump_block(self, ea, b): 24 | # iterate over all block instructions 25 | print("dumping block %x" % (ea, )) 26 | for ins in b: 27 | print(" %x: insn %s" % (ins.ea, ins.opname)) 28 | 29 | 30 | class vds7_hooks_t(ida_hexrays.Hexrays_Hooks): 31 | def maturity(self, cfunc, maturity): 32 | if maturity == ida_hexrays.CMAT_BUILT: 33 | cbv = cblock_visitor_t() 34 | cbv.apply_to(cfunc.body, None) 35 | return 0 36 | 37 | 38 | if ida_hexrays.init_hexrays_plugin(): 39 | vds7_hooks = vds7_hooks_t() 40 | vds7_hooks.hook() 41 | else: 42 | print('cblock visitor: hexrays is not available.') 43 | -------------------------------------------------------------------------------- /examples/hexrays/vds_create_hint.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: decompiler hints 3 | 4 | description: 5 | Handle `ida_hexrays.hxe_create_hint` notification using hooks, 6 | to return our own. 7 | 8 | If the object under the cursor is: 9 | 10 | * a function call, prefix the original decompiler hint with `==> ` 11 | * a local variable declaration, replace the hint with our own in 12 | the form of `!{varname}` (where `{varname}` is replaced with the 13 | variable name) 14 | * an `if` statement, replace the hint with our own, saying "condition" 15 | """ 16 | 17 | import ida_idaapi 18 | import ida_hexrays 19 | 20 | class hint_hooks_t(ida_hexrays.Hexrays_Hooks): 21 | def create_hint(self, vu): 22 | if vu.get_current_item(ida_hexrays.USE_MOUSE): 23 | cit = vu.item.citype 24 | if cit == ida_hexrays.VDI_LVAR: 25 | return 1, "!%s" % vu.item.l.name, 1 26 | elif cit == ida_hexrays.VDI_EXPR: 27 | ce = vu.item.e 28 | if ce.op == ida_hexrays.cot_call: 29 | return 0, "==> ", 1 30 | if ce.op == ida_hexrays.cit_if: 31 | return 1, "condition", 1 32 | return 0 33 | 34 | vds_hooks = hint_hooks_t() 35 | vds_hooks.hook() 36 | -------------------------------------------------------------------------------- /examples/hexrays/vds_modify_user_lvars.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: modifying local variables 3 | 4 | description: 5 | Use a `ida_hexrays.user_lvar_modifier_t` to modify names, 6 | comments and/or types of local variables. 7 | """ 8 | 9 | import ida_hexrays 10 | import ida_typeinf 11 | 12 | import idc 13 | 14 | class my_modifier_t(ida_hexrays.user_lvar_modifier_t): 15 | def __init__(self, name_prefix="", cmt_prefix="", new_types={}): 16 | ida_hexrays.user_lvar_modifier_t.__init__(self) 17 | self.name_prefix = name_prefix 18 | self.cmt_prefix = cmt_prefix 19 | self.new_types = new_types 20 | 21 | def modify_lvars(self, lvars): 22 | def log(msg): 23 | print("modify_lvars: %s" % msg) 24 | """Note: lvars.lvvec contains only variables modified from the defaults. 25 | To change other variables, you can, for example, first use rename_lvar() 26 | so they get added to this list, then use modify_user_lvar_info() or modify_lvars(). 27 | """ 28 | log("len(lvars.lvvec) = %d" % len(lvars.lvvec)) 29 | log("lvars.lmaps.size() = %d" % lvars.lmaps.size()) 30 | log("lvars.stkoff_delta = %d" % lvars.stkoff_delta) 31 | log("lvars.ulv_flags = %x" % lvars.ulv_flags) 32 | 33 | for idx, one in enumerate(lvars.lvvec): 34 | def varlog(msg): 35 | log("var #%d: %s" % (idx, msg)) 36 | varlog("name = '%s'" % one.name) 37 | varlog("type = '%s'" % one.type._print()) 38 | varlog("cmt = '%s'" % one.cmt) 39 | varlog("size = %d" % one.size) 40 | varlog("flags = %x" % one.flags) 41 | new_type = self.new_types.get(one.name) 42 | if new_type: 43 | ida_typeinf.parse_decl(one.type, None, new_type, 0) 44 | one.name = self.name_prefix + one.name 45 | one.cmt = self.cmt_prefix + one.cmt 46 | 47 | return True 48 | 49 | 50 | def modify_function_lvars(name_prefix="patched_", cmt_prefix="(patched) ", new_types={}): 51 | ea = idc.here() 52 | my_mod = my_modifier_t( 53 | name_prefix=name_prefix, 54 | cmt_prefix=cmt_prefix, 55 | new_types=new_types) 56 | ida_hexrays.modify_user_lvars(ea, my_mod) 57 | -------------------------------------------------------------------------------- /examples/idbs/be_ornot_be.i64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HexRaysSA/IDAPython/bd1c5927f0ad44048fcd9cc42a9a743504e6c7a0/examples/idbs/be_ornot_be.i64 -------------------------------------------------------------------------------- /examples/idbs/be_ornot_be.idb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HexRaysSA/IDAPython/bd1c5927f0ad44048fcd9cc42a9a743504e6c7a0/examples/idbs/be_ornot_be.idb -------------------------------------------------------------------------------- /examples/idphooks/ana_emu_out.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: override some parts of the processor module 3 | 4 | description: 5 | Implements disassembly of BUG_INSTR used in Linux kernel 6 | BUG() macro, which is architecturally undefined and is not 7 | disassembled by IDA's ARM module 8 | 9 | See Linux/arch/arm/include/asm/bug.h for more info 10 | """ 11 | 12 | import ida_idp 13 | import ida_bytes 14 | import ida_segregs 15 | 16 | ITYPE_BUGINSN = ida_idp.CUSTOM_INSN_ITYPE + 10 17 | MNEM_WIDTH = 16 18 | 19 | class MyHooks(ida_idp.IDP_Hooks): 20 | 21 | def __init__(self): 22 | ida_idp.IDP_Hooks.__init__(self) 23 | self.reported = [] 24 | 25 | def ev_ana_insn(self, insn): 26 | t_reg = ida_idp.str2reg("T") 27 | t = ida_segregs.get_sreg(insn.ea, t_reg) 28 | if t==0 and ida_bytes.get_wide_dword(insn.ea) == 0xE7F001F2: 29 | insn.itype = ITYPE_BUGINSN 30 | insn.size = 4 31 | elif t!=0 and ida_bytes.get_wide_word(insn.ea) == 0xde02: 32 | insn.itype = ITYPE_BUGINSN 33 | insn.size = 2 34 | return insn.size 35 | 36 | def ev_emu_insn(self, insn): 37 | if insn.itype == ITYPE_BUGINSN: 38 | return 1 # do not add any xrefs (stop code flow) 39 | # use default processing for all other functions 40 | return 0 41 | 42 | def ev_out_mnem(self, outctx): 43 | if outctx.insn.itype == ITYPE_BUGINSN: 44 | outctx.out_custom_mnem("BUG_INSTR", MNEM_WIDTH) 45 | return 1 46 | return 0 47 | 48 | if ida_idp.ph.id == ida_idp.PLFM_ARM: 49 | bahooks = MyHooks() 50 | bahooks.hook() 51 | print("BUG_INSTR processor extension installed") 52 | else: 53 | warning("This script only supports ARM files") 54 | -------------------------------------------------------------------------------- /examples/idphooks/assemble.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: an `ida_idp.IDP_Hooks.assembly` implementation 3 | 4 | description: 5 | We add support for assembling the following pseudo instructions: 6 | 7 | * "zero eax" -> xor eax, eax 8 | * "nothing" -> nop 9 | """ 10 | 11 | import ida_idp 12 | import idautils 13 | 14 | #-------------------------------------------------------------------------- 15 | class assemble_idp_hook_t(ida_idp.IDP_Hooks): 16 | def ev_assemble(self, ea, cs, ip, use32, line): 17 | line = line.strip() 18 | if line == "zero eax": 19 | return b"\x33\xC0" 20 | elif line == "nothing": 21 | # Decode current instruction to figure out its size 22 | cmd = idautils.DecodeInstruction(ea) 23 | if cmd: 24 | # NOP all the instruction bytes 25 | return b"\x90" * cmd.size 26 | return None 27 | 28 | 29 | #--------------------------------------------------------------------- 30 | # Remove an existing hook on second run 31 | try: 32 | idp_hook_stat = "un" 33 | print("IDP hook: checking for hook...") 34 | idphook 35 | print("IDP hook: unhooking....") 36 | idphook.unhook() 37 | del idphook 38 | except: 39 | print("IDP hook: not installed, installing now....") 40 | idp_hook_stat = "" 41 | idphook = assemble_idp_hook_t() 42 | idphook.hook() 43 | 44 | print("IDP hook %sinstalled. Run the script again to %sinstall" % (idp_hook_stat, idp_hook_stat)) 45 | -------------------------------------------------------------------------------- /examples/index.css: -------------------------------------------------------------------------------- 1 | 2 | body 3 | { 4 | margin: 3%; 5 | } 6 | 7 | .exp-col 8 | { 9 | cursor: pointer; 10 | padding: 0 4px 0 6px; 11 | } 12 | 13 | .collapsed-entry .details 14 | { 15 | display: none; 16 | } 17 | 18 | .example-entry .details 19 | { 20 | margin-left: 3%; 21 | padding: 6px; 22 | background-color: #eef; 23 | } 24 | 25 | a 26 | { 27 | text-decoration: none; 28 | } -------------------------------------------------------------------------------- /examples/pyqt/populate_pluginform_with_pyqt_widgets.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: adding PyQt5 widgets into an `ida_kernwin.PluginForm` 3 | 4 | description: 5 | Using `ida_kernwin.PluginForm.FormToPyQtWidget`, this script 6 | converts IDA's own dockable widget into a type that is 7 | recognized by PyQt5, which then enables populating it with 8 | regular Qt widgets. 9 | """ 10 | 11 | from PyQt5 import QtCore, QtGui, QtWidgets 12 | 13 | class MyPluginFormClass(ida_kernwin.PluginForm): 14 | def OnCreate(self, form): 15 | """ 16 | Called when the widget is created 17 | """ 18 | 19 | # Get parent widget 20 | self.parent = self.FormToPyQtWidget(form) 21 | self.PopulateForm() 22 | 23 | 24 | def PopulateForm(self): 25 | # Create layout 26 | layout = QtWidgets.QVBoxLayout() 27 | 28 | layout.addWidget( 29 | QtWidgets.QLabel("Hello from PyQt")) 30 | layout.addWidget( 31 | QtWidgets.QLabel("Hello from IDAPython")) 32 | 33 | self.parent.setLayout(layout) 34 | 35 | 36 | def OnClose(self, form): 37 | """ 38 | Called when the widget is closed 39 | """ 40 | pass 41 | 42 | plg = MyPluginFormClass() 43 | plg.Show("PyQt hello world") 44 | -------------------------------------------------------------------------------- /examples/uihooks/func_chooser_coloring.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: using `ida_kernwin.UI_Hooks.get_chooser_item_attrs` to override some defaults 3 | 4 | description: 5 | color the function in the Function window according to its size. 6 | The larger the function, the darker the color. 7 | """ 8 | 9 | import ida_kernwin 10 | import ida_funcs 11 | import math 12 | 13 | class func_chooser_coloring_hooks_t(ida_kernwin.UI_Hooks): 14 | def __init__(self): 15 | ida_kernwin.UI_Hooks.__init__(self) 16 | self.colors = [0x808080 + (32-i) * 0x400 for i in range(32-5)] 17 | 18 | def get_chooser_item_attrs(self, chobj, n, attrs): 19 | if attrs.color != 0xFFFFFFFF: 20 | return # the color is already set 21 | ea = chobj.get_ea(n) 22 | fn = ida_funcs.get_func(ea) 23 | size = fn.size() 24 | if size < 32: 25 | return # do not color small functions 26 | attrs.color = self.colors[int(math.log2(size))] 27 | 28 | fcch = func_chooser_coloring_hooks_t() 29 | fcch.hook() 30 | ida_kernwin.enable_chooser_item_attrs("Functions", True) 31 | 32 | -------------------------------------------------------------------------------- /examples/uihooks/prevent_jump.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: taking precedence over actions 3 | 4 | description: 5 | Using `ida_kernwin.UI_Hooks.preprocess_action`, it is possible 6 | to respond to a command instead of the action that would 7 | otherwise do it. 8 | """ 9 | 10 | import ida_kernwin 11 | 12 | class prevent_jump_t(ida_kernwin.UI_Hooks): 13 | def preprocess_action(self, action_name): 14 | if action_name == "JumpEnter": 15 | print("Inhibiting 'jump'!") 16 | return 1 17 | return 0 18 | 19 | phh = prevent_jump_t() 20 | if phh.hook(): 21 | print("From now on, pressing will prevent IDA from jumping. "\ 22 | +"Please type 'phh.unhook()' to revert to the normal behavior.") 23 | -------------------------------------------------------------------------------- /examples/widgets/misc/add_menus.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: adding custom menus to IDA 3 | 4 | description: 5 | It is possible to add custom menus to IDA, either at the 6 | toplevel (i.e., into the menubar), or as submenus of existing 7 | menus. 8 | 9 | Notes: 10 | 11 | * the same action can be present in more than 1 menu 12 | * this example does not deal with context menus 13 | 14 | keywords: actions 15 | """ 16 | 17 | import ida_kernwin 18 | 19 | # Create custom menus 20 | ida_kernwin.create_menu("MyToplevelMenu", "&Custom menu", "View") 21 | ida_kernwin.create_menu("MySubMenu", "Custom s&ubmenu", "View/Print internal flags") 22 | 23 | # Create some actions 24 | class greeter_t(ida_kernwin.action_handler_t): 25 | def __init__(self, greetings): 26 | ida_kernwin.action_handler_t.__init__(self) 27 | self.greetings = greetings 28 | 29 | def activate(self, ctx): 30 | print(self.greetings) 31 | 32 | def update(self, ctx): 33 | return ida_kernwin.AST_ENABLE_ALWAYS 34 | 35 | ACTION_NAME_0 = "my_action_0" 36 | ACTION_NAME_1 = "my_action_1" 37 | for action_name, greetings in [ 38 | (ACTION_NAME_0, "Hello, world"), 39 | (ACTION_NAME_1, "Hi there"), 40 | ]: 41 | desc = ida_kernwin.action_desc_t( 42 | action_name, "Say \"%s\"" % greetings, greeter_t(greetings)) 43 | if ida_kernwin.register_action(desc): 44 | print("Registered action \"%s\"" % action_name) 45 | 46 | 47 | # Then, let's attach some actions to them - both core actions 48 | # and custom ones is allowed (also, any action can be attached 49 | # to multiple menus.) 50 | for action_name, path in [ 51 | (ACTION_NAME_0, "Custom menu"), 52 | (ACTION_NAME_0, "View/Custom submenu/"), 53 | (ACTION_NAME_1, "Custom menu"), 54 | (ACTION_NAME_1, "View/Custom submenu/"), 55 | ("About", "Custom menu"), 56 | ("About", "View/Custom submenu/"), 57 | ]: 58 | ida_kernwin.attach_action_to_menu( 59 | path, 60 | action_name, 61 | ida_kernwin.SETMENU_INS) 62 | -------------------------------------------------------------------------------- /examples/widgets/tabular_views/custom/choose_multi.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: A widget showing data in a tabular fashion, providing multiple selection 3 | 4 | description: 5 | Similar to @{choose}, but with multiple selection 6 | 7 | keywords: chooser, actions 8 | 9 | see_also: choose, chooser_with_folders 10 | """ 11 | 12 | from ida_kernwin import Choose 13 | 14 | class MyChoose(Choose): 15 | 16 | def __init__(self, title, nb = 5): 17 | Choose.__init__( 18 | self, 19 | title, 20 | [ ["Bit", Choose.CHCOL_HEX | 10] ], 21 | flags = Choose.CH_MULTI) 22 | self.items = [ str(1 << x) for x in range(nb) ] 23 | 24 | def OnGetSize(self): 25 | return len(self.items) 26 | 27 | def OnGetLine(self, n): 28 | return [self.items[n]] 29 | 30 | def OnSelectLine(self, n): 31 | self.deflt = n # save current selection 32 | return (Choose.NOTHING_CHANGED, ) 33 | 34 | def OnDeleteLine(self, indices): 35 | new_items = [] 36 | for idx, item in enumerate(self.items): 37 | if idx not in indices: 38 | new_items.append(item) 39 | self.items = new_items 40 | return [Choose.ALL_CHANGED] + indices 41 | 42 | def show(self, num): 43 | self.deflt = [x 44 | for x in range(len(self.items)) 45 | if (num & (1 << x)) != 0] 46 | if self.Show(True) < 0: 47 | return 0 48 | return sum([(1 << x) for x in self.deflt]) 49 | 50 | 51 | # ----------------------------------------------------------------------- 52 | def test_choose(num): 53 | c = MyChoose("Choose - sample 2", nb = 5) 54 | return c.show(num) 55 | 56 | # ----------------------------------------------------------------------- 57 | if __name__ == '__main__': 58 | print(test_choose(11)) 59 | -------------------------------------------------------------------------------- /examples/widgets/tabular_views/custom/func_chooser.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: An alternative view over the list of functions 3 | 4 | description: 5 | Partially re-implements the "Functions" widget present in 6 | IDA, with a custom widget. 7 | 8 | keywords: chooser, functions 9 | 10 | see_also: choose, choose_multi, chooser_with_folders 11 | """ 12 | 13 | import idautils 14 | import idc 15 | import ida_funcs 16 | import ida_kernwin 17 | 18 | class my_funcs_t(ida_kernwin.Choose): 19 | 20 | def __init__(self, title): 21 | ida_kernwin.Choose.__init__( 22 | self, 23 | title, 24 | [ ["Address", 10 | ida_kernwin.Choose.CHCOL_HEX], 25 | ["Name", 30 | ida_kernwin.Choose.CHCOL_PLAIN | ida_kernwin.Choose.CHCOL_FNAME] ]) 26 | self.items = [] 27 | self.icon = ida_kernwin.get_icon_id_by_name("resources/menu/OpenFunctions.svg") 28 | 29 | def OnInit(self): 30 | self.items = [ [hex(x), ida_funcs.get_func_name(x), x] 31 | for x in idautils.Functions() ] 32 | return True 33 | 34 | def OnGetSize(self): 35 | return len(self.items) 36 | 37 | def OnGetLine(self, n): 38 | return self.items[n] 39 | 40 | def OnDeleteLine(self, n): 41 | ea = self.items[n][2] 42 | idc.del_func(ea) 43 | return (ida_kernwin.Choose.ALL_CHANGED, n) 44 | 45 | def OnGetEA(self, n): 46 | return self.items[n][2] 47 | 48 | def OnRefresh(self, n): 49 | self.OnInit() 50 | # try to preserve the cursor 51 | return [ida_kernwin.Choose.ALL_CHANGED] + self.adjust_last_item(n) 52 | 53 | def OnClose(self): 54 | print("closed ", self.title) 55 | 56 | 57 | def show_my_funcs_t(modal=False): 58 | c = my_funcs_t("My functions list") 59 | c.Show(modal=modal) 60 | 61 | if __name__ == "__main__": 62 | show_my_funcs_t() 63 | 64 | -------------------------------------------------------------------------------- /examples/widgets/waitbox/show_and_hide_waitbox.py: -------------------------------------------------------------------------------- 1 | """ 2 | summary: showing, updating & hiding the progress dialog 3 | 4 | description: 5 | Using the progress dialog (aka 'wait box') primitives. 6 | 7 | keywords: actions 8 | """ 9 | 10 | import time 11 | import random 12 | 13 | import ida_kernwin 14 | import ida_hexrays 15 | import ida_funcs 16 | 17 | import idautils 18 | 19 | perform_decompilation=False 20 | 21 | # Note: this try/except block below is just there to 22 | # let us (at Hex-Rays) test this script in various 23 | # situations. 24 | try: 25 | perform_decompilation = under_test__perform_decompilation 26 | except: 27 | pass 28 | 29 | 30 | step_sleep = 0.5 31 | ida_kernwin.show_wait_box("Processing") 32 | try: 33 | all_eas = list(idautils.Functions()) 34 | neas = len(all_eas) 35 | for i, ea in enumerate(all_eas): 36 | if ida_kernwin.user_cancelled(): 37 | break 38 | ida_kernwin.replace_wait_box("Processing; step %d/%d" % (i+1, neas)) 39 | 40 | if perform_decompilation: 41 | if not ida_hexrays.decompile(ea): 42 | print("Decompilation failure: %x" % ea) 43 | 44 | time.sleep(step_sleep * random.random()) 45 | finally: 46 | ida_kernwin.hide_wait_box() 47 | 48 | 49 | -------------------------------------------------------------------------------- /extapi.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EXTAPI_HPP 2 | #define EXTAPI_HPP 3 | 4 | #include 5 | 6 | #ifdef Py_LIMITED_API 7 | typedef void *Py_tracefunc; 8 | struct PyCompilerFlags; 9 | # if PY_MAJOR_VERSION < 3 || PY_MINOR_VERSION < 9 10 | struct PyFrameObject; 11 | # endif 12 | #else 13 | # include 14 | #endif 15 | 16 | typedef void PyEval_SetTrace_t(Py_tracefunc, PyObject *); 17 | 18 | typedef int PyRun_SimpleStringFlags_t(const char *, PyCompilerFlags *); 19 | typedef PyObject *PyRun_StringFlags_t(const char *, int, PyObject *, PyObject *, PyCompilerFlags *); 20 | 21 | #if PY_MAJOR_VERSION < 3 22 | typedef PyObject *Py_CompileString_t(const char *, const char *, int); 23 | #else 24 | typedef PyObject *Py_CompileStringExFlags_t(const char *, const char *, int, PyCompilerFlags *, int); 25 | #endif 26 | 27 | typedef PyObject *PyFunction_New_t(PyObject *, PyObject *); 28 | typedef PyObject *PyFunction_GetCode_t(PyObject *); 29 | 30 | typedef int _PyLong_AsByteArray_t(PyObject *, unsigned char *, size_t, int, int); 31 | 32 | typedef int PyEval_ThreadsInitialized_t(void); 33 | typedef void PyEval_InitThreads_t(void); 34 | typedef int Py_NoSiteFlag_t; 35 | 36 | struct ext_api_t 37 | { 38 | qstring lib_path; 39 | void *lib_handle; 40 | 41 | PyEval_SetTrace_t *PyEval_SetTrace_ptr; 42 | PyRun_SimpleStringFlags_t *PyRun_SimpleStringFlags_ptr; 43 | PyRun_StringFlags_t *PyRun_StringFlags_ptr; 44 | #if PY_MAJOR_VERSION < 3 45 | Py_CompileString_t *Py_CompileString_ptr; 46 | #else 47 | Py_CompileStringExFlags_t *Py_CompileStringExFlags_ptr; 48 | #endif 49 | 50 | PyFunction_New_t *PyFunction_New_ptr; 51 | PyFunction_GetCode_t *PyFunction_GetCode_ptr; 52 | _PyLong_AsByteArray_t *_PyLong_AsByteArray_ptr; 53 | PyEval_ThreadsInitialized_t *PyEval_ThreadsInitialized_ptr; 54 | PyEval_InitThreads_t *PyEval_InitThreads_ptr; 55 | int *Py_NoSiteFlag_ptr; 56 | 57 | ext_api_t() { memset(this, 0, sizeof(*this)); } 58 | ~ext_api_t() { clear(); } 59 | 60 | bool load(qstring *errbuf); 61 | void clear(); 62 | }; 63 | 64 | extern ext_api_t extapi; 65 | 66 | #endif // EXTAPI_HPP 67 | -------------------------------------------------------------------------------- /idaapi.i: -------------------------------------------------------------------------------- 1 | // We need this file just to avoid a warning from swig that the input file is not 2 | // specifed precisely and swig had to find it using the header path. 3 | 4 | %include "swig/idaapi.i" -------------------------------------------------------------------------------- /idapython.cfg: -------------------------------------------------------------------------------- 1 | // Alert before loading automatic scripts found in current directory 2 | // swig_runtime_dataN, sitecustomize and usercustomize 3 | ALERT_AUTO_SCRIPTS = YES 4 | 5 | // Remove current directory from import search path 6 | REMOVE_CWD_SYS_PATH = YES 7 | 8 | // Script timeout (in seconds) 9 | // (A value of 0 disables the timeout) 10 | SCRIPT_TIMEOUT = 3 11 | 12 | // Should the plugin automatically load a backward-compatibility-providing 13 | // 'idaapi' wrapper module? 14 | AUTOIMPORT_COMPAT_IDAAPI = YES 15 | 16 | // Is IDAPython namespace-aware? 17 | // If yes, then plugins, loaders & processor modules will each be loaded 18 | // within their own namespace, preventing namespace pollution. 19 | NAMESPACE_AWARE = YES 20 | 21 | // Should results be printed by 'sys.displayhook'? 22 | REPL_USE_SYS_DISPLAYHOOK = YES 23 | 24 | // Should directories derived from $IDAUSR (e.g., ~/.idapro/python) be added to sys.path? 25 | IDAPYTHON_IDAUSR_SYSPATH = YES 26 | -------------------------------------------------------------------------------- /idapython.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HexRaysSA/IDAPython/bd1c5927f0ad44048fcd9cc42a9a743504e6c7a0/idapython.png -------------------------------------------------------------------------------- /makedep.cfg: -------------------------------------------------------------------------------- 1 | ida_exclude+=fuzzer.hpp 2 | -------------------------------------------------------------------------------- /options.lnt: -------------------------------------------------------------------------------- 1 | -esym(4100, obj) // unreferenced formal parameter 2 | -esym(2586, PySys_SetPath) // w2586 Function 'PySys_SetPath' is deprecated 3 | 4 | -------------------------------------------------------------------------------- /out_of_tree/parsed_notifications.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HexRaysSA/IDAPython/bd1c5927f0ad44048fcd9cc42a9a743504e6c7a0/out_of_tree/parsed_notifications.zip -------------------------------------------------------------------------------- /python/idaapi.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | 4 | ${IMPORTS} 5 | 6 | # guerilla-patch a few unfortunate overrides 7 | from ida_funcs import set_func_start 8 | from ida_funcs import set_func_end 9 | from ida_dbg import dbg_can_query 10 | 11 | class idaapi_Cvar(object): 12 | def __init__(self): 13 | # prevent endless recursion 14 | object.__setattr__(self, "modules", "${MODULES}".split(",")) 15 | object.__setattr__(self, "cvars_entries", dict()) 16 | 17 | def _get_module_cvar(self, modname): 18 | mod = sys.modules["ida_%s" % modname] 19 | cv, entries = None, None 20 | if hasattr(mod, "cvar"): 21 | cv = getattr(mod, "cvar") 22 | entries = [] 23 | if cv: 24 | if modname in self.cvars_entries.keys(): 25 | entries = self.cvars_entries[modname] 26 | else: 27 | # Parse 'str' version of cvar. Although this is braindeader than 28 | # braindead, I'm not sure there's another way to do it. 29 | entries_s = str(cv) 30 | entries = entries_s[1:len(entries_s)-1].split(", ") 31 | self.cvars_entries[modname] = entries 32 | return cv, entries 33 | 34 | def __getattr__(self, attr): 35 | for mod in self.modules: 36 | cv, entries = self._get_module_cvar(mod) 37 | if cv and attr in entries: 38 | return getattr(cv, attr) 39 | 40 | def __setattr__(self, attr, value): 41 | for mod in self.modules: 42 | cv, entries = self._get_module_cvar(mod) 43 | if cv and attr in entries: 44 | setattr(cv, attr, value) 45 | 46 | 47 | cvar = idaapi_Cvar() 48 | -------------------------------------------------------------------------------- /pywraps/py_bytes_find_bytes.hpp: -------------------------------------------------------------------------------- 1 | 2 | // /* 3 | // TODO's 4 | // * `start_ea` -> `range_start` 5 | // * `end_ea` -> `range_size` 6 | // * parse_binpat_str => warning in case of error 7 | // * make start_ea the 1st argument? 8 | // * "4f fd" fails parsing 9 | // * masks don't honor the bit granularity: anything non-0 is considered as a match 10 | // */ 11 | 12 | 13 | // 14 | // 15 | 16 | 17 | // 18 | inline bytevec_t __to_bytevec(const bytevec_t &in) 19 | { 20 | return in; 21 | } 22 | // 23 | 24 | -------------------------------------------------------------------------------- /pywraps/py_dbg.py: -------------------------------------------------------------------------------- 1 | # 2 | import ida_idaapi 3 | import ida_idd 4 | import ida_expr 5 | 6 | def get_tev_reg_val(tev, reg): 7 | rv = ida_idd.regval_t() 8 | if get_insn_tev_reg_val(tev, reg, rv): 9 | if rv.rvtype == ida_idd.RVT_INT: 10 | return rv.ival 11 | 12 | def get_tev_reg_mem_qty(tev): 13 | ti = tev_info_t() 14 | if get_tev_info(tev, ti): 15 | mis = memreg_infos_t() 16 | if get_insn_tev_reg_mem(tev, mis): 17 | return mis.size() 18 | 19 | def get_tev_reg_mem(tev, idx): 20 | mis = memreg_infos_t() 21 | if get_insn_tev_reg_mem(tev, mis): 22 | if idx < mis.size(): 23 | return mis[idx].bytes 24 | 25 | def get_tev_reg_mem_ea(tev, idx): 26 | ti = tev_info_t() 27 | if get_tev_info(tev, ti): 28 | mis = memreg_infos_t() 29 | if get_insn_tev_reg_mem(tev, mis): 30 | if idx >= 0 and idx < mis.size(): 31 | return mis[idx].ea 32 | 33 | def send_dbg_command(command): 34 | """ 35 | Send a direct command to the debugger backend, and 36 | retrieve the result as a string. 37 | 38 | Note: any double-quotes in 'command' must be backslash-escaped. 39 | Note: this only works with some debugger backends: Bochs, WinDbg, GDB. 40 | 41 | Returns: (True, ) on success, or (False, ) on failure 42 | """ 43 | rv = ida_expr.idc_value_t() 44 | err = ida_expr.eval_idc_expr(rv, ida_idaapi.BADADDR, """send_dbg_command("%s");""" % command) 45 | if err: 46 | return False, "eval_idc_expr() failed: %s" % err 47 | vtype = ord(rv.vtype) 48 | if vtype == ida_expr.VT_STR: 49 | s = rv.c_str() 50 | if "IDC_FAILURE" in s: 51 | return False, "eval_idc_expr() reported an error: %s" % s 52 | return True, s 53 | elif vtype == ida_expr.VT_LONG: 54 | return True, str(rv.num) 55 | else: 56 | return False, "eval_idc_expr(): wrong return type: %d" % vtype 57 | 58 | move_bpt_to_grp = set_bpt_group 59 | 60 | # 61 | -------------------------------------------------------------------------------- /pywraps/py_fpro_end.py: -------------------------------------------------------------------------------- 1 | # 2 | qfile_t_from_fp = qfile_t.from_fp 3 | qfile_t_from_capsule = qfile_t.from_capsule 4 | qfile_t_tmpfile = qfile_t.tmpfile 5 | # 6 | -------------------------------------------------------------------------------- /pywraps/py_frame.hpp: -------------------------------------------------------------------------------- 1 | // 2 | 3 | //------------------------------------------------------------------------- 4 | inline bool is_funcarg_off(const func_t *pfn, uval_t frameoff) 5 | { 6 | processor_t &ph = PH; 7 | return ph.is_funcarg_off(pfn, frameoff); 8 | } 9 | 10 | //------------------------------------------------------------------------- 11 | inline sval_t lvar_off(const func_t *pfn, uval_t frameoff) 12 | { 13 | processor_t &ph = PH; 14 | return ph.lvar_off(pfn, frameoff); 15 | } 16 | // 17 | -------------------------------------------------------------------------------- /pywraps/py_funcs.py: -------------------------------------------------------------------------------- 1 | # 2 | import ida_idaapi 3 | @ida_idaapi.replfun 4 | def calc_thunk_func_target(*args): 5 | if len(args) == 2: 6 | pfn, rawptr = args 7 | target, fptr = calc_thunk_func_target.__dict__["orig"](pfn) 8 | import ida_pro 9 | ida_pro.ea_pointer.frompointer(rawptr).assign(fptr) 10 | return target 11 | else: 12 | return calc_thunk_func_target.__dict__["orig"](*args) 13 | # 14 | -------------------------------------------------------------------------------- /pywraps/py_idc.hpp: -------------------------------------------------------------------------------- 1 | 2 | // 3 | //------------------------------------------------------------------------- 4 | inline void mark_position( 5 | ea_t ea, 6 | int lnnum, 7 | short x, 8 | short y, 9 | int32 slot, 10 | const char *comment) 11 | { 12 | idaplace_t ip(ea, lnnum); 13 | renderer_info_t ri; 14 | ri.rtype = TCCRT_FLAT; 15 | ri.pos.cx = x; 16 | ri.pos.cy = y; 17 | lochist_entry_t loc(&ip, ri); 18 | bookmarks_t::mark(loc, slot, nullptr, comment, nullptr); 19 | } 20 | 21 | //------------------------------------------------------------------------- 22 | inline ea_t get_marked_pos(int32 slot) 23 | { 24 | idaplace_t ip(inf_get_min_ea(), 0); 25 | renderer_info_t ri; 26 | lochist_entry_t loc(&ip, ri); 27 | uint32 uslot = uint32(slot); 28 | return bookmarks_t::get(&loc, nullptr, &uslot, nullptr) 29 | ? loc.place()->toea() 30 | : BADADDR; 31 | } 32 | 33 | //------------------------------------------------------------------------- 34 | inline PyObject *get_mark_comment(int32 slot) 35 | { 36 | qstring desc; 37 | idaplace_t ip(inf_get_min_ea(), 0); 38 | renderer_info_t ri; 39 | lochist_entry_t loc(&ip, ri); 40 | if ( bookmarks_t::get_desc(&desc, loc, slot, nullptr) ) 41 | return PyUnicode_FromString(desc.c_str()); 42 | else 43 | Py_RETURN_NONE; 44 | } 45 | // 46 | 47 | -------------------------------------------------------------------------------- /pywraps/py_idp_idbhooks.hpp: -------------------------------------------------------------------------------- 1 | 2 | // 3 | 4 | //--------------------------------------------------------------------------- 5 | // IDB hooks 6 | //--------------------------------------------------------------------------- 7 | ssize_t idaapi IDB_Callback(void *ud, int notification_code, va_list va); 8 | struct IDB_Hooks : public hooks_base_t 9 | { 10 | // hookgenIDB:methodsinfo_decl 11 | 12 | IDB_Hooks(uint32 _flags=0, uint32 _hkcb_flags=HKCB_GLOBAL) 13 | : hooks_base_t("ida_idp.IDB_Hooks", IDB_Callback, HT_IDB, _flags, _hkcb_flags) {} 14 | 15 | bool hook() { return hooks_base_t::hook(); } 16 | bool unhook() { return hooks_base_t::unhook(); } 17 | #ifdef TESTABLE_BUILD 18 | PyObject *dump_state(bool assert_all_reimplemented=false) { return hooks_base_t::dump_state(mappings, mappings_size, assert_all_reimplemented); } 19 | #endif 20 | 21 | // hookgenIDB:methods 22 | 23 | ssize_t dispatch(int code, va_list va) 24 | { 25 | switch ( code ) 26 | { 27 | // hookgenIDB:notifications 28 | } 29 | return 0; 30 | } 31 | }; 32 | 33 | //------------------------------------------------------------------------- 34 | PyObject *get_idb_notifier_addr(PyObject *) 35 | { 36 | return _wrap_addr_in_pycapsule((void *) IDB_Callback); 37 | } 38 | 39 | //------------------------------------------------------------------------- 40 | PyObject *get_idb_notifier_ud_addr(IDB_Hooks *hooks) 41 | { 42 | return _wrap_addr_in_pycapsule(hooks); 43 | } 44 | // 45 | 46 | 47 | // 48 | 49 | // hookgenIDB:methodsinfo_def 50 | 51 | //--------------------------------------------------------------------------- 52 | ssize_t idaapi IDB_Callback(void *ud, int code, va_list va) 53 | { 54 | // hookgenIDB:safecall=IDB_Hooks 55 | } 56 | 57 | // 58 | -------------------------------------------------------------------------------- /pywraps/py_idp_idbhooks.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | 4 | class _processor_t_Trampoline_IDB_Hooks(IDB_Hooks): 5 | def __init__(self, proc): 6 | IDB_Hooks.__init__(self, ida_idaapi.HBF_CALL_WITH_NEW_EXEC | ida_idaapi.HBF_VOLATILE_METHOD_SET) 7 | import weakref 8 | self.proc = weakref.ref(proc) 9 | for key in dir(self): 10 | if not key.startswith("_") and not key in ["proc"]: 11 | thing = getattr(self, key) 12 | if hasattr(thing, "__call__"): 13 | setattr(self, key, self.__make_parent_caller(key)) 14 | 15 | def __dummy(self, *args): 16 | return 0 17 | 18 | def __make_parent_caller(self, key): 19 | # we can't get the method at this point, as it'll be bound 20 | # to the processor_t instance, which means it'll increase 21 | # the reference counting 22 | def call_parent(*args): 23 | return getattr(self.proc(), key, self.__dummy)(*args) 24 | return call_parent 25 | 26 | # 27 | 28 | -------------------------------------------------------------------------------- /pywraps/py_idp_notify_when.py: -------------------------------------------------------------------------------- 1 | # 2 | import weakref 3 | class _notify_when_dispatcher_t: 4 | 5 | class _callback_t: 6 | def __init__(self, fun): 7 | self.fun = fun 8 | self.slots = 0 9 | 10 | class _IDP_Hooks(IDP_Hooks): 11 | def __init__(self, dispatcher): 12 | IDP_Hooks.__init__(self) 13 | self.dispatcher = weakref.ref(dispatcher) 14 | 15 | def ev_newfile(self, name): 16 | return self.dispatcher().dispatch(ida_idaapi.NW_OPENIDB, 0) 17 | 18 | def ev_oldfile(self, name): 19 | return self.dispatcher().dispatch(ida_idaapi.NW_OPENIDB, 1) 20 | 21 | class _IDB_Hooks(IDB_Hooks): 22 | def __init__(self, dispatcher): 23 | IDB_Hooks.__init__(self) 24 | self.dispatcher = weakref.ref(dispatcher) 25 | 26 | def closebase(self): 27 | return self.dispatcher().dispatch(ida_idaapi.NW_CLOSEIDB) 28 | 29 | 30 | def __init__(self): 31 | self.idp_hooks = self._IDP_Hooks(self) 32 | self.idp_hooks.hook() 33 | self.idb_hooks = self._IDB_Hooks(self) 34 | self.idb_hooks.hook() 35 | self.callbacks = [] 36 | 37 | def _find(self, fun): 38 | for idx, cb in enumerate(self.callbacks): 39 | if cb.fun == fun: 40 | return idx, cb 41 | return None, None 42 | 43 | def dispatch(self, slot, *args): 44 | for cb in self.callbacks[:]: # make a copy, since dispatch() could cause some callbacks to disappear 45 | if (cb.slots & slot) != 0: 46 | cb.fun(slot, *args) 47 | return 0 48 | 49 | def notify_when(self, when, fun): 50 | _, cb = self._find(fun) 51 | if cb is None: 52 | cb = self._callback_t(fun) 53 | self.callbacks.append(cb) 54 | if (when & ida_idaapi.NW_REMOVE) != 0: 55 | cb.slots &= ~(when & ~ida_idaapi.NW_REMOVE) 56 | else: 57 | cb.slots |= when 58 | if cb.slots == 0: 59 | idx, cb = self._find(cb.fun) 60 | del self.callbacks[idx] 61 | return True 62 | 63 | # 64 | -------------------------------------------------------------------------------- /pywraps/py_ieee.hpp: -------------------------------------------------------------------------------- 1 | // 2 | typedef bytevec_t bytevec16_t; 3 | // 4 | 5 | -------------------------------------------------------------------------------- /pywraps/py_ieee.py: -------------------------------------------------------------------------------- 1 | 2 | # Note that we DON'T define EZERO/EONE/ETWO to be fpvalue_t objects, 3 | # because there is no way to make them read-only, which means EZERO 4 | # could represent something entirely different from zero if the 5 | # user mistakenly modifies it. 6 | 7 | # 8 | EZERO = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 9 | EONE = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\xFF\x3F" 10 | ETWO = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x40" 11 | # 12 | -------------------------------------------------------------------------------- /pywraps/py_kernwin_end.py: -------------------------------------------------------------------------------- 1 | # 2 | place_t_as_idaplace_t = place_t.as_idaplace_t 3 | place_t_as_simpleline_place_t = place_t.as_simpleline_place_t 4 | place_t_as_tiplace_t = place_t.as_tiplace_t 5 | # 6 | -------------------------------------------------------------------------------- /pywraps/py_kernwin_idaview.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | #------------------------------------------------------------------------- 4 | # IDAViewWrapper 5 | #------------------------------------------------------------------------- 6 | import _ida_kernwin 7 | class IDAViewWrapper(CustomIDAMemo): 8 | """ 9 | Deprecated. Use View_Hooks instead. 10 | 11 | Because the lifecycle of an IDAView is not trivial to track (e.g., a user 12 | might close, then re-open the same disassembly view), this wrapper doesn't 13 | bring anything superior to the View_Hooks: quite the contrary, as the 14 | latter is much more generic (and better maps IDA's internal model.) 15 | """ 16 | def __init__(self, title): 17 | CustomIDAMemo.__init__(self) 18 | self._title = title 19 | 20 | def Bind(self): 21 | rc = _ida_kernwin.pyidag_bind(self) 22 | if rc: 23 | self.hook() 24 | return rc 25 | 26 | def Unbind(self): 27 | rc = _ida_kernwin.pyidag_unbind(self) 28 | if rc: 29 | self.unhook() 30 | return rc 31 | 32 | # 33 | -------------------------------------------------------------------------------- /pywraps/py_kernwin_viewhooks.hpp: -------------------------------------------------------------------------------- 1 | 2 | // 3 | 4 | //--------------------------------------------------------------------------- 5 | // View hooks 6 | //--------------------------------------------------------------------------- 7 | ssize_t idaapi View_Callback(void *ud, int notification_code, va_list va); 8 | struct View_Hooks : public hooks_base_t 9 | { 10 | // hookgenVIEW:methodsinfo_decl 11 | 12 | View_Hooks(uint32 _flags=0, uint32 _hkcb_flags=HKCB_GLOBAL) 13 | : hooks_base_t("ida_kernwin.View_Hooks", View_Callback, HT_VIEW, _flags, _hkcb_flags) {} 14 | 15 | bool hook() { return hooks_base_t::hook(); } 16 | bool unhook() { return hooks_base_t::unhook(); } 17 | #ifdef TESTABLE_BUILD 18 | PyObject *dump_state(bool assert_all_reimplemented=false) { return hooks_base_t::dump_state(mappings, mappings_size, assert_all_reimplemented); } 19 | #endif 20 | 21 | // hookgenVIEW:methods 22 | 23 | ssize_t dispatch(int code, va_list va) 24 | { 25 | switch ( code ) 26 | { 27 | // hookgenVIEW:notifications 28 | } 29 | return 0; 30 | } 31 | }; 32 | 33 | // 34 | 35 | 36 | // 37 | 38 | // hookgenVIEW:methodsinfo_def 39 | 40 | //--------------------------------------------------------------------------- 41 | ssize_t idaapi View_Callback(void *ud, int code, va_list va) 42 | { 43 | // hookgenVIEW:safecall=View_Hooks 44 | } 45 | // 46 | -------------------------------------------------------------------------------- /pywraps/py_lines.py: -------------------------------------------------------------------------------- 1 | # 2 | import _ida_idaapi 3 | import _ida_lines 4 | 5 | # ---------------- Color escape sequence defitions ------------------------- 6 | COLOR_ADDR_SIZE = 16 if _ida_idaapi.BADADDR == 0xFFFFFFFFFFFFFFFF else 8 7 | SCOLOR_FG_MAX = '\x28' # Max color number 8 | cvar = _ida_lines.cvar 9 | SCOLOR_OPND1 = chr(cvar.COLOR_ADDR+1) # Instruction operand 1 10 | SCOLOR_OPND2 = chr(cvar.COLOR_ADDR+2) # Instruction operand 2 11 | SCOLOR_OPND3 = chr(cvar.COLOR_ADDR+3) # Instruction operand 3 12 | SCOLOR_OPND4 = chr(cvar.COLOR_ADDR+4) # Instruction operand 4 13 | SCOLOR_OPND5 = chr(cvar.COLOR_ADDR+5) # Instruction operand 5 14 | SCOLOR_OPND6 = chr(cvar.COLOR_ADDR+6) # Instruction operand 6 15 | SCOLOR_UTF8 = chr(cvar.COLOR_ADDR+10) # Following text is UTF-8 encoded 16 | 17 | # ---------------- Line prefix colors -------------------------------------- 18 | PALETTE_SIZE = (cvar.COLOR_FG_MAX+_ida_lines.COLOR_BG_MAX) 19 | 20 | def requires_color_esc(c): 21 | """ 22 | Checks if the given character requires escaping 23 | @param c: character (string of one char) 24 | @return: Boolean 25 | """ 26 | t = ord(c[0]) 27 | return c >= COLOR_ON and c <= COLOR_INV 28 | 29 | def COLSTR(str, tag): 30 | """ 31 | Utility function to create a colored line 32 | @param str: The string 33 | @param tag: Color tag constant. One of SCOLOR_XXXX 34 | """ 35 | return SCOLOR_ON + tag + str + SCOLOR_OFF + tag 36 | 37 | # 38 | -------------------------------------------------------------------------------- /pywraps/py_lumina.hpp: -------------------------------------------------------------------------------- 1 | 2 | // 3 | 4 | //------------------------------------------------------------------------- 5 | bool py_extract_type_from_metadata(tinfo_t *out, const bytevec_t &in) 6 | { 7 | md_type_parts_t tp; 8 | if ( !in.empty() ) 9 | { 10 | const uchar *ptr = in.begin(); 11 | const uchar *end = in.end(); 12 | extract_type_from_metadata(&tp, ptr, end); 13 | out->deserialize(nullptr, &tp.type, &tp.fields); 14 | } 15 | return tp.userti; 16 | } 17 | 18 | //------------------------------------------------------------------------- 19 | PyObject *py_split_metadata(const metadata_t &md) 20 | { 21 | PyObject *py_dict = PyDict_New(); 22 | 23 | metadata_iterator_t p(md); 24 | while ( p.next() ) 25 | { 26 | newref_t py_key(PyInt_FromLong(p.key)); 27 | newref_t py_value(PyBytes_FromStringAndSize((const char *) p.data, p.size)); 28 | // PyDict_SetItem doesn't "steal" references; hence the 'newref_t's above. 29 | PyDict_SetItem(py_dict, py_key.o, py_value.o); 30 | } 31 | 32 | return py_dict; 33 | } 34 | 35 | // 36 | -------------------------------------------------------------------------------- /pywraps/py_moves.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __PYMOVES__ 2 | #define __PYMOVES__ 3 | // 4 | // 5 | #endif 6 | -------------------------------------------------------------------------------- /pywraps/py_moves.py: -------------------------------------------------------------------------------- 1 | # 2 | import ida_kernwin 3 | # 4 | -------------------------------------------------------------------------------- /pywraps/py_moves_end.py: -------------------------------------------------------------------------------- 1 | # 2 | bookmarks_t_erase = bookmarks_t.erase 3 | bookmarks_t_find_index = bookmarks_t.find_index 4 | bookmarks_t_get = bookmarks_t.get 5 | bookmarks_t_get_desc = bookmarks_t.get_desc 6 | bookmarks_t_get_dirtree_id = bookmarks_t.get_dirtree_id 7 | bookmarks_t_mark = bookmarks_t.mark 8 | bookmarks_t_size = bookmarks_t.size 9 | # 10 | -------------------------------------------------------------------------------- /pywraps/py_nalt.py: -------------------------------------------------------------------------------- 1 | # 2 | _real_get_switch_info = get_switch_info 3 | def get_switch_info(*args): 4 | if len(args) == 1: 5 | si, ea = switch_info_t(), args[0] 6 | else: 7 | si, ea = args 8 | return None if _real_get_switch_info(si, ea) <= 0 else si 9 | def get_abi_name(): 10 | import ida_typeinf 11 | return ida_typeinf.get_abi_name() 12 | # for backward compatibility 13 | get_initial_version = get_initial_idb_version 14 | # 15 | -------------------------------------------------------------------------------- /pywraps/py_name.hpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------- 2 | // 3 | // 4 | 5 | //------------------------------------------------------------------------ 6 | // 7 | //------------------------------------------------------------------------ 8 | PyObject *get_debug_names(ea_t ea1, ea_t ea2, bool return_list=false) 9 | { 10 | // Get debug names 11 | ea_name_vec_t names; 12 | PYW_GIL_CHECK_LOCKED_SCOPE(); 13 | SWIG_PYTHON_THREAD_BEGIN_ALLOW; 14 | get_debug_names(&names, ea1, ea2); 15 | SWIG_PYTHON_THREAD_END_ALLOW; 16 | PyObject *dict = Py_BuildValue("{}"); 17 | if ( dict != nullptr ) 18 | { 19 | ea_t last_ea = BADADDR; 20 | PyObject *list = nullptr; 21 | for ( ea_name_vec_t::iterator it = names.begin(); it != names.end(); ++it ) 22 | { 23 | PyObject *name_obj = PyUnicode_FromString(it->name.c_str()); 24 | if ( it->ea != last_ea ) 25 | { 26 | if ( return_list ) 27 | list = PyList_New(0); 28 | PyObject *ea_obj = Py_BuildValue(PY_BV_EA, bvea_t(it->ea)); 29 | PyDict_SetItem(dict, ea_obj, return_list ? list : name_obj); 30 | last_ea = it->ea; 31 | } 32 | if ( return_list ) 33 | PyList_Append(list, name_obj); 34 | } 35 | } 36 | return dict; 37 | } 38 | 39 | //------------------------------------------------------------------------- 40 | inline qstring py_get_ea_name(ea_t ea, int gtn_flags=0) 41 | { 42 | qstring out; 43 | get_ea_name(&out, ea, gtn_flags); 44 | return out; 45 | } 46 | 47 | //------------------------------------------------------------------------- 48 | PyObject *py_validate_name(const char *name, nametype_t type, int flags=SN_NOCHECK) 49 | { 50 | qstring qname(name); 51 | if ( validate_name(&qname, type, flags) ) 52 | return PyUnicode_FromStringAndSize(qname.c_str(), qname.length()); 53 | else 54 | Py_RETURN_NONE; 55 | } 56 | // 57 | -------------------------------------------------------------------------------- /pywraps/py_name.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | # 4 | import _ida_idaapi 5 | import _ida_funcs 6 | import bisect 7 | 8 | 9 | class NearestName(object): 10 | """ 11 | Utility class to help find the nearest name in a given ea/name dictionary 12 | """ 13 | def __init__(self, ea_names): 14 | self.update(ea_names) 15 | 16 | 17 | def update(self, ea_names): 18 | """Updates the ea/names map""" 19 | self._names = ea_names 20 | self._addrs = list(ea_names.keys()) 21 | self._addrs.sort() 22 | 23 | 24 | def find(self, ea): 25 | """ 26 | Returns a tupple (ea, name, pos) that is the nearest to the passed ea 27 | If no name is matched then None is returned 28 | """ 29 | pos = bisect.bisect_left(self._addrs, ea) 30 | # no match 31 | if pos >= len(self._addrs): 32 | return None 33 | # exact match? 34 | if self._addrs[pos] != ea: 35 | pos -= 1 # go to previous element 36 | if pos < 0: 37 | return None 38 | return self[pos] 39 | 40 | 41 | def _get_item(self, index): 42 | ea = self._addrs[index] 43 | return (ea, self._names[ea], index) 44 | 45 | 46 | def __iter__(self): 47 | return (self._get_item(index) for index in range(0, len(self._addrs))) 48 | 49 | 50 | def __getitem__(self, index): 51 | """Returns the tupple (ea, name, index)""" 52 | if index > len(self._addrs): 53 | raise StopIteration 54 | return self._get_item(index) 55 | 56 | def calc_gtn_flags(fromaddr, ea): 57 | """ 58 | Calculate flags for get_ea_name() function 59 | 60 | @param fromaddr: the referring address. May be BADADDR. 61 | @param ea: linear address 62 | 63 | @return: flags 64 | """ 65 | gtn_flags = 0 66 | if fromaddr != _ida_idaapi.BADADDR: 67 | pfn = _ida_funcs.get_func(fromaddr) 68 | if _ida_funcs.func_contains(pfn, ea): 69 | gtn_flags = GN_LOCAL 70 | return gtn_flags 71 | 72 | # 73 | -------------------------------------------------------------------------------- /pywraps/py_netnode_end.py: -------------------------------------------------------------------------------- 1 | # 2 | netnode_exist = netnode.exist 3 | # 4 | -------------------------------------------------------------------------------- /pywraps/py_range.hpp: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 4 | -------------------------------------------------------------------------------- /pywraps/py_range.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | import ida_idaapi 4 | # 5 | -------------------------------------------------------------------------------- /pywraps/py_search.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | -------------------------------------------------------------------------------- /pywraps/py_search.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # 4 | -------------------------------------------------------------------------------- /pywraps/py_segment.hpp: -------------------------------------------------------------------------------- 1 | 2 | // 3 | void segment_t_start_ea_set(segment_t *segm, ea_t newea) 4 | { 5 | if ( getseg(segm->start_ea) == segm ) 6 | { 7 | PyErr_SetString(PyExc_AttributeError, "Can't modify start_ea, please use set_segm_start() instead"); 8 | } 9 | else 10 | { 11 | segm->start_ea = newea; 12 | } 13 | } 14 | 15 | ea_t segment_t_start_ea_get(segment_t *segm) 16 | { 17 | return segm->start_ea; 18 | } 19 | 20 | void segment_t_end_ea_set(segment_t *segm, ea_t newea) 21 | { 22 | if ( getseg(segm->start_ea) == segm ) 23 | { 24 | PyErr_SetString(PyExc_AttributeError, "Can't modify end_ea, please use set_segm_end() instead"); 25 | } 26 | else 27 | { 28 | segm->end_ea = newea; 29 | } 30 | } 31 | 32 | ea_t segment_t_end_ea_get(segment_t *segm) 33 | { 34 | return segm->end_ea; 35 | } 36 | // 37 | 38 | // 39 | //-------------------------------------------------------------------------- 40 | /* 41 | # 42 | def get_defsr(s, reg): 43 | """ 44 | Deprecated, use instead: 45 | value = s.defsr[reg] 46 | """ 47 | pass 48 | # 49 | */ 50 | sel_t get_defsr(segment_t *s, int reg) 51 | { 52 | return s != nullptr && reg >= 0 && reg < SREG_NUM ? s->defsr[reg] : BADSEL; 53 | } 54 | 55 | //-------------------------------------------------------------------------- 56 | /* 57 | # 58 | def set_defsr(s, reg, value): 59 | """ 60 | Deprecated, use instead: 61 | s.defsr[reg] = value 62 | """ 63 | pass 64 | # 65 | */ 66 | void set_defsr(segment_t *s, int reg, sel_t value) 67 | { 68 | if ( s != nullptr && reg >= 0 && reg < SREG_NUM ) 69 | s->defsr[reg] = value; 70 | } 71 | 72 | //-------------------------------------------------------------------------- 73 | int py_rebase_program(PyObject *delta, int flags) 74 | { 75 | int rc = MOVE_SEGM_PARAM; 76 | uint64 num_delta; 77 | if ( PyW_GetNumber(delta, &num_delta) ) 78 | rc = rebase_program(adiff_t(num_delta), flags); 79 | else 80 | PyErr_SetString(PyExc_TypeError, "Expected a delta in bytes"); 81 | return rc; 82 | } 83 | // 84 | -------------------------------------------------------------------------------- /pywraps/py_typeinf.py: -------------------------------------------------------------------------------- 1 | # 2 | 3 | import ida_idaapi 4 | ida_idaapi._listify_types( 5 | reginfovec_t) 6 | 7 | # 8 | # When turning off BC695, 'idati' would still remain available 9 | # 10 | _real_cvar = cvar 11 | _notify_idati = ida_idaapi._make_one_time_warning_message("idati", "get_idati()") 12 | 13 | class _wrap_cvar(object): 14 | def __getattr__(self, attr): 15 | if attr == "idati": 16 | _notify_idati() 17 | return get_idati() 18 | return getattr(_real_cvar, attr) 19 | 20 | def __setattr__(self, attr, value): 21 | if attr != "idati": 22 | setattr(_real_cvar, attr, value) 23 | 24 | cvar = _wrap_cvar() 25 | 26 | # for compatilibity: 27 | sc_auto = SC_AUTO 28 | sc_ext = SC_EXT 29 | sc_friend = SC_FRIEND 30 | sc_reg = SC_REG 31 | sc_stat = SC_STAT 32 | sc_type = SC_TYPE 33 | sc_unk = SC_UNK 34 | sc_virt = SC_VIRT 35 | 36 | TERR_SAVE = TERR_SAVE_ERROR 37 | TERR_WRONGNAME = TERR_BAD_NAME 38 | 39 | BADORD = 0xFFFFFFFF 40 | 41 | enum_member_vec_t = edmvec_t 42 | enum_member_t = edm_t 43 | udt_member_t = udm_t 44 | tinfo_t.find_udt_member = tinfo_t.find_udm 45 | 46 | # 47 | -------------------------------------------------------------------------------- /pywraps/py_ua.py: -------------------------------------------------------------------------------- 1 | # 2 | ua_mnem = print_insn_mnem 3 | # 4 | -------------------------------------------------------------------------------- /pywraps/py_xref.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | 4 | import ida_idaapi 5 | ida_idaapi._listify_types( 6 | casevec_t) 7 | 8 | # 9 | -------------------------------------------------------------------------------- /pywraps/pywraps.hpp: -------------------------------------------------------------------------------- 1 | // Just a proxy header 2 | #include "../pywraps.hpp" -------------------------------------------------------------------------------- /pywraps/pywraps.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pywraps", "pywraps.vcxproj", "{F43D6BB8-B7D6-486A-82E5-BABBA9848525}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Rel64|Win32 = Rel64|Win32 10 | Release|Win32 = Release|Win32 11 | Release64|Win32 = Release64|Win32 12 | SemiDebug|Win32 = SemiDebug|Win32 13 | SemiDebugx64|Win32 = SemiDebugx64|Win32 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {F43D6BB8-B7D6-486A-82E5-BABBA9848525}.Debug|Win32.ActiveCfg = Debug|Win32 17 | {F43D6BB8-B7D6-486A-82E5-BABBA9848525}.Debug|Win32.Build.0 = Debug|Win32 18 | {F43D6BB8-B7D6-486A-82E5-BABBA9848525}.Rel64|Win32.ActiveCfg = Rel64|Win32 19 | {F43D6BB8-B7D6-486A-82E5-BABBA9848525}.Rel64|Win32.Build.0 = Rel64|Win32 20 | {F43D6BB8-B7D6-486A-82E5-BABBA9848525}.Release|Win32.ActiveCfg = Release|Win32 21 | {F43D6BB8-B7D6-486A-82E5-BABBA9848525}.Release|Win32.Build.0 = Release|Win32 22 | {F43D6BB8-B7D6-486A-82E5-BABBA9848525}.Release64|Win32.ActiveCfg = Release64|Win32 23 | {F43D6BB8-B7D6-486A-82E5-BABBA9848525}.Release64|Win32.Build.0 = Release64|Win32 24 | {F43D6BB8-B7D6-486A-82E5-BABBA9848525}.SemiDebug|Win32.ActiveCfg = SemiDebug|Win32 25 | {F43D6BB8-B7D6-486A-82E5-BABBA9848525}.SemiDebug|Win32.Build.0 = SemiDebug|Win32 26 | {F43D6BB8-B7D6-486A-82E5-BABBA9848525}.SemiDebugx64|Win32.ActiveCfg = SemiDebugx64|Win32 27 | {F43D6BB8-B7D6-486A-82E5-BABBA9848525}.SemiDebugx64|Win32.Build.0 = SemiDebugx64|Win32 28 | EndGlobalSection 29 | GlobalSection(SolutionProperties) = preSolution 30 | HideSolutionNode = FALSE 31 | EndGlobalSection 32 | EndGlobal 33 | -------------------------------------------------------------------------------- /stublib/makelibpython3-stub.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #generate libpython3-stub.so.with the same symbols as libpython3.M.so for linking IDAPython 4 | set VERSION=3.5 5 | set ABIFLAGS=`python3-config --abilags` 6 | set LDVERSION= $(VERSION)$(ABIFLAGS) 7 | set PYLIB=`python3-config --configdir`/libpython$(LDVERSION).so 8 | python makestub2.py $(PYLIB) >stub.c 9 | gcc -pthread -shared -Wl,--no-as-needed -o libpython3-stub.so -Wl,-hlibpython3.so stub6.c 10 | -------------------------------------------------------------------------------- /stublib/makelibpython3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #generate libpython3.so which forwads to actual libpython3.M.so for running IDA (copy it next to IDA's binary) 4 | LDFLAGS=`python3-config --ldflags` 5 | gcc -pthread -shared -Wl,--no-as-needed -o libpython3.so -Wl,-hlibpython3.so $LDFLAGS 6 | -------------------------------------------------------------------------------- /stublib/makestub2.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import re 3 | 4 | # idea borrowed from implib-gen.py 5 | def collect_syms(f, symlist = None): 6 | p = subprocess.Popen(["readelf", "-sDW", f], stdout=subprocess.PIPE, stderr=subprocess.PIPE) 7 | (out, err) = p.communicate() 8 | out = out.decode('utf-8') 9 | err = err.decode('utf-8') 10 | if p.returncode != 0 or err: 11 | error("readelf failed with retcode %d: %s" % (p.returncode, err)) 12 | 13 | toc = None 14 | syms = [] 15 | warn_versioned = False 16 | for line in out.splitlines(): 17 | line = line.strip() 18 | if not line: 19 | continue 20 | # Num Buc: Value Size Type Bind Vis Ndx Name 21 | # 492 0: 00000000005ebac0 400 OBJECT GLOBAL DEFAULT 24 PyTraceBack_Type 22 | # 493 0: 00000000001cfc30 13 FUNC GLOBAL DEFAULT 12 Py_CompileString 23 | 24 | words = re.split(r' +', line) 25 | if line.startswith('Num'): # Header? 26 | if toc is not None: 27 | error("multiple headers in output of readelf") 28 | toc = {} 29 | for i, n in enumerate(words): 30 | # Colons are different across readelf versions so get rid of them. 31 | n = n.replace(':', '') 32 | toc[i] = n 33 | elif toc is not None: 34 | sym = {k: words[i] for i, k in toc.items()} 35 | if '@' in sym['Name']: 36 | name, ver = sym['Name'].split('@') 37 | sym['Name'] = name 38 | sym['Version'] = ver 39 | if not warn_versioned: 40 | # TODO 41 | warn("library %s contains versioned symbols which are NYI" % f) 42 | warn_versioned = True 43 | else: 44 | sym['Version'] = None 45 | if symlist and sym['Name'] not in symlist: 46 | continue 47 | syms.append(sym) 48 | 49 | if toc is None: 50 | error("failed to analyze %s" % f) 51 | 52 | return syms 53 | 54 | import sys 55 | 56 | syms = collect_syms(sys.argv[1]) 57 | for sym in syms: 58 | nm = sym['Name'] 59 | sz = sym['Size'] 60 | tp =sym['Type'] 61 | if sz != '0': 62 | if tp=="FUNC": 63 | print (" void %s(){};" % nm) 64 | elif tp =="OBJECT": 65 | print ('__asm__(".globl %s; .pushsection .data; .type %s,@object; .size %s, %s; %s: .zero %s; .popsection");' %(nm, nm, nm, sz, nm, sz)) 66 | -------------------------------------------------------------------------------- /stublib/readme.txt: -------------------------------------------------------------------------------- 1 | These files create stub libraries for linking and running IDA without linking to a specific libpython3.M.so 2 | This is achieved by linking to a libpython3.so library which forwards to the actual libpython3.M.so 3 | - makelibpython3.sh makes such libpython3.so if your Python distribution does not provide one (recipe stolen from Python's Makefile) 4 | - makelibpython3-stub.sh makes a libpython3-stub.so which exports the same symbols 5 | as original libpython3.M.so but has SONAME of libpython3.so. 6 | It can be used to check for missing symbols during linking but use libpython3.so at runtime 7 | - makestub2.py creates a C file to create this stub by parsing the original symbol table from libpython3.M.so 8 | 9 | -------------------------------------------------------------------------------- /swig/allins.i: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | %} 4 | 5 | // Ignore the unnedded externals 6 | %ignore Instructions; 7 | 8 | %include "allins.hpp" 9 | -------------------------------------------------------------------------------- /swig/auto.i: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | %} 4 | 5 | %include "auto.hpp" 6 | 7 | -------------------------------------------------------------------------------- /swig/dirtree.i: -------------------------------------------------------------------------------- 1 | 2 | %{ 3 | #include 4 | %} 5 | 6 | %apply SWIGTYPE *DISOWN { dirspec_t *ds }; 7 | 8 | %template(direntry_vec_t) qvector; 9 | %template(dirtree_cursor_vec_t) qvector; 10 | 11 | // 12 | // compat 13 | // 14 | %ignore dirtree_get_nodename; 15 | %ignore dirtree_set_nodename; 16 | 17 | %extend dirspec_t { 18 | %pythoncode { 19 | nodename = id 20 | } 21 | } 22 | 23 | %extend dirtree_t { 24 | %pythoncode { 25 | get_nodename = get_id 26 | set_nodename = set_id 27 | } 28 | } 29 | 30 | %include "dirtree.hpp" 31 | -------------------------------------------------------------------------------- /swig/entry.i: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | %} 4 | 5 | %include "entry.hpp" 6 | -------------------------------------------------------------------------------- /swig/fixup.i: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | %} 4 | 5 | %ignore apply_fixup; 6 | %ignore fixup_handler_t; 7 | %ignore register_custom_fixup; 8 | %ignore unregister_custom_fixup; 9 | 10 | %cstring_output_qstring_returning_charptr( 11 | 1, 12 | qstring *buf, 13 | ea_t source); // fixup_data_t::get_desc 14 | 15 | %cstring_output_qstring_returning_charptr( 16 | 1, 17 | qstring *buf, 18 | ea_t source, 19 | const fixup_data_t &fd); // get_fixup_desc 20 | 21 | %include "fixup.hpp" 22 | -------------------------------------------------------------------------------- /swig/fpro.i: -------------------------------------------------------------------------------- 1 | %inline %{ 2 | // 3 | .// 4 | %} 5 | 6 | %ignore fread2bytes; 7 | %ignore fread4bytes; 8 | %ignore fread8bytes; 9 | %ignore freadbytes; 10 | %ignore fwrite2bytes; 11 | %ignore fwrite4bytes; 12 | %ignore fwrite8bytes; 13 | %ignore fwritebytes; 14 | %ignore qaccess; 15 | %ignore qcopyfile; 16 | %ignore qeprintf; 17 | //%ignore qfclose; 18 | %ignore qfgetc; 19 | %ignore qfgets; 20 | %ignore qflush; 21 | %ignore qfopen; 22 | %ignore qfprintf; 23 | %ignore qfputc; 24 | %ignore qfputs; 25 | %ignore qfread; 26 | %ignore qfscanf; 27 | %ignore qfseek; 28 | %ignore qfsize; 29 | %ignore qftell; 30 | %ignore qfwrite; 31 | %ignore qgetline; 32 | %ignore qgets; 33 | %ignore qmove; 34 | %ignore qprintf; 35 | %ignore qrename; 36 | %ignore qtmpdir; 37 | %ignore qtmpfile; 38 | %ignore qtmpnam; 39 | %ignore qunlink; 40 | %ignore qveprintf; 41 | %ignore qvfprintf; 42 | %ignore qvfscanf; 43 | %ignore qvprintf; 44 | 45 | %include "fpro.h" 46 | 47 | %pythoncode %{ 48 | # 49 | # 50 | %} 51 | -------------------------------------------------------------------------------- /swig/frame.i: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | %} 4 | 5 | %ignore add_frame_spec_member; 6 | %ignore del_stkvars; 7 | %ignore set_llabel; 8 | %ignore get_llabel_ea; 9 | %ignore get_llabel; 10 | 11 | %ignore add_stkvar; 12 | 13 | %ignore delete_wrong_frame_info; 14 | %ignore get_func_frame(tinfo_t *tif, ea_t ea); 15 | 16 | %template(xreflist_t) qvector; 17 | 18 | // 19 | // 20 | 21 | %inline %{ 22 | // 23 | // 24 | %} 25 | 26 | %include "frame.hpp" 27 | -------------------------------------------------------------------------------- /swig/gdl.i: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | %} 4 | 5 | %ignore gdl_graph_t::gen_gdl; 6 | %ignore gdl_graph_t::gen_dot; 7 | %ignore gdl_graph_t::path_exists; 8 | 9 | %ignore cancellable_graph_t::padding; 10 | %ignore cancellable_graph_t::check_cancel; 11 | 12 | %ignore intmap_t; 13 | %ignore intset_t; 14 | %ignore intseq_t; 15 | %ignore node_set_t; 16 | %ignore qflow_chart_t::blocks; 17 | %ignore flow_chart_t; 18 | %ignore setup_graph_subsystem; 19 | %ignore qbasic_block_t::succ; 20 | %ignore qbasic_block_t::pred; 21 | 22 | %include "gdl.hpp" 23 | 24 | %extend qflow_chart_t 25 | { 26 | qbasic_block_t *__getitem__(int n) 27 | { 28 | return &(self->blocks[n]); 29 | } 30 | } 31 | 32 | %pythoncode %{ 33 | # 34 | # 35 | %} 36 | -------------------------------------------------------------------------------- /swig/idaapi.i: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include 4 | %} 5 | 6 | %{ 7 | #include 8 | 9 | #ifdef HAVE_SSIZE_T 10 | #define _SSIZE_T_DEFINED 1 11 | #endif 12 | 13 | // 14 | // 15 | %} 16 | 17 | %ignore parse_command_line3; 18 | %rename (parse_command_line3) py_parse_command_line; 19 | 20 | %constant ea_t BADADDR = ea_t(0-1); 21 | %constant ea32_t BADADDR32 = ea32_t(0-1ULL); 22 | %constant ea64_t BADADDR64 = ea64_t(0-1ULL); 23 | %constant sel_t BADSEL = sel_t(0-1); 24 | %constant size_t SIZE_MAX = size_t(0-1); 25 | /* %constant nodeidx_t BADNODE = nodeidx_t(0-1); */ 26 | 27 | %include "typemaps.i" 28 | 29 | %include "cstring.i" 30 | %include "carrays.i" 31 | %include "cpointer.i" 32 | 33 | %pythoncode %{ 34 | # 35 | # 36 | %} 37 | 38 | 39 | %inline %{ 40 | // 41 | // 42 | %} 43 | 44 | //------------------------------------------------------------------------- 45 | %inline %{ 46 | // 47 | // 48 | %} 49 | -------------------------------------------------------------------------------- /swig/idbhooks.i: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | %} 4 | 5 | %ignore IDB_Callback; 6 | 7 | %inline %{ 8 | // 9 | // 10 | %} 11 | 12 | %{ 13 | // 14 | // 15 | %} 16 | -------------------------------------------------------------------------------- /swig/idc.i: -------------------------------------------------------------------------------- 1 | 2 | // This contains helpers needed for idc.py to work correctly 3 | 4 | %{ 5 | #include 6 | #include 7 | %} 8 | 9 | %{ 10 | // 11 | // 12 | %} 13 | 14 | %inline %{ 15 | // 16 | // 17 | %} 18 | 19 | %pythoncode %{ 20 | # 21 | # 22 | %} 23 | -------------------------------------------------------------------------------- /swig/lines.i: -------------------------------------------------------------------------------- 1 | // FIXME: These should be fixed 2 | %ignore requires_color_esc; 3 | // Ignore va_list versions 4 | %ignore vadd_extra_line; 5 | // Kernel-only and unexported symbols 6 | %ignore get_last_pfxlen; 7 | %ignore closing_comment; 8 | %ignore close_comment; 9 | %ignore init_lines; 10 | %ignore save_lines; 11 | %ignore align_down_to_stack; 12 | %ignore align_up_to_stack; 13 | %ignore encoder_t; 14 | %ignore file_producer_t; 15 | 16 | %typemap(default) const void *owner { 17 | $1 = nullptr; 18 | } 19 | 20 | %ignore generate_disassembly; 21 | %rename (generate_disassembly) py_generate_disassembly; 22 | 23 | %ignore tag_remove; 24 | %rename (tag_remove) py_tag_remove; 25 | 26 | %ignore tag_addr; 27 | %rename (tag_addr) py_tag_addr; 28 | 29 | %ignore tag_skipcodes; 30 | %rename (tag_skipcodes) py_tag_skipcodes; 31 | 32 | %ignore tag_skipcode; 33 | %rename (tag_skipcode) py_tag_skipcode; 34 | 35 | %ignore tag_advance; 36 | %rename (tag_advance) py_tag_advance; 37 | 38 | %typemap(argout) (qstring *buf, ea_t ea, int what) 39 | { 40 | // typemap(argout) (qstring *buf, ea_t ea, int what) 41 | Py_XDECREF(resultobj); 42 | if (result >= 0) 43 | { 44 | resultobj = PyUnicode_FromStringAndSize((const char *) $1->c_str(), $1->length()); 45 | } 46 | else 47 | { 48 | Py_INCREF(Py_None); 49 | resultobj = Py_None; 50 | } 51 | } 52 | 53 | // 54 | // 55 | 56 | %include "lines.hpp" 57 | 58 | %pywraps_nonnul_argument_prototype( 59 | PyObject *py_tag_remove(const char *nonnul_instr), 60 | const char *nonnul_instr); 61 | 62 | %inline %{ 63 | // 64 | // 65 | %} 66 | 67 | %pythoncode %{ 68 | # 69 | # 70 | %} 71 | -------------------------------------------------------------------------------- /swig/linput.i: -------------------------------------------------------------------------------- 1 | %inline %{ 2 | // 3 | // 4 | %} 5 | -------------------------------------------------------------------------------- /swig/mergemod.i: -------------------------------------------------------------------------------- 1 | 2 | %{ 3 | #include 4 | %} 5 | 6 | %ignore create_std_modmerge_handlers; 7 | %rename(create_std_modmerge_handlers) create_std_modmerge_handlers2; 8 | %ignore create_std_modmerge_handlers2(merge_handler_params_t &,int,moddata_diff_helper_t &,merge_node_info2_t const *); 9 | 10 | // Prototype of the custom function to create merge handlers 11 | %ignore create_merge_handlers; 12 | 13 | // idaman void ida_export create_std_modmerge_handlers2( 14 | // merge_handler_params_t &mhp, 15 | // int moddata_id, 16 | // moddata_diff_helper_t &helper, 17 | // const merge_node_info2_t *merge_node_info=nullptr, 18 | // size_t n_merge_node_info=0); 19 | %define_merge_handler_typemap(merge_node_info, n_merge_node_info); 20 | 21 | %include "mergemod.hpp" 22 | 23 | -------------------------------------------------------------------------------- /swig/micro.org: -------------------------------------------------------------------------------- 1 | * DONE gen_microcode() creates a new mba_t; user must delete it 2 | * DONE mop_t::cstr must be dup'd when set 3 | * DONE mop_t ownership might not be transferred when setting to a parent (and thus neither is mcallarg_t) 4 | * TODO how about all visitors? scif_visitor_t, mop_visitor_t, ... 5 | * TODO 6 | -------------------------------------------------------------------------------- /swig/offset.i: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | %} 4 | %include "offset.hpp" 5 | -------------------------------------------------------------------------------- /swig/problems.i: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | %} 4 | 5 | %include "problems.hpp" 6 | -------------------------------------------------------------------------------- /swig/range.i: -------------------------------------------------------------------------------- 1 | %ignore rangeset_t::count; 2 | %ignore rangeset_t::lower_bound; 3 | %ignore rangeset_t::upper_bound; 4 | %ignore rangeset_t::move_chunk; 5 | %ignore rangeset_t::check_move_args; 6 | %ignore range64_t; 7 | %ignore range64vec_t; 8 | 9 | %template(rangevec_base_t) qvector; 10 | %template(array_of_rangesets) qvector; 11 | 12 | %inline %{ 13 | // 14 | // 15 | %} 16 | 17 | %extend rangeset_t { 18 | %pythoncode { 19 | def __getitem__(self, idx): 20 | return self.getrange(idx) 21 | 22 | __len__ = nranges 23 | __iter__ = ida_idaapi._bounded_getitem_iterator 24 | } 25 | }; 26 | 27 | %pythoncode %{ 28 | # 29 | # 30 | %} 31 | 32 | %include "range.hpp" 33 | -------------------------------------------------------------------------------- /swig/registry.i: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | %} 4 | %ignore reg_bin_op; 5 | %ignore reg_str_get; 6 | %ignore reg_str_set; 7 | %ignore reg_int_op; 8 | %ignore _RVN_; 9 | %ignore REG_VAL_NAME; 10 | %ignore REG_BOOL_FUNC; 11 | %ignore REG_INT_FUNC; 12 | %ignore MAX_HISTORY_FILES_DEF; 13 | %ignore regkey_history; 14 | %ignore max_history_files; 15 | %ignore regget_history; 16 | %ignore reg_update_history; 17 | %ignore reg_history_size_truncate; 18 | 19 | %ignore reg_read_string; 20 | %rename (reg_read_string) py_reg_read_string; 21 | 22 | %ignore reg_data_type; 23 | %rename (reg_data_type) py_reg_data_type; 24 | 25 | %ignore reg_read_binary; 26 | %rename (reg_read_binary) py_reg_read_binary; 27 | %ignore reg_write_binary; 28 | %rename (reg_write_binary) py_reg_write_binary; 29 | 30 | %ignore reg_read_binary_part; 31 | 32 | /* inline bool reg_subkey_subkeys(qstrvec_t *out, const char *name) */ 33 | %ignore reg_subkey_subkeys; 34 | %rename (reg_subkey_subkeys) py_reg_subkey_subkeys; 35 | %ignore reg_subkey_values; 36 | %rename (reg_subkey_values) py_reg_subkey_values; 37 | %ignore reg_subkey_children; 38 | 39 | %apply qstrvec_t *out { qstrvec_t *list }; 40 | 41 | %{ 42 | // 43 | // 44 | %} 45 | 46 | %inline %{ 47 | // 48 | // 49 | %} 50 | 51 | // 52 | // 53 | 54 | %include "registry.hpp" 55 | -------------------------------------------------------------------------------- /swig/search.i: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | %} 4 | %apply int * OUTPUT { int *opnum }; 5 | 6 | %ignore search; 7 | %ignore user2bin; 8 | 9 | %ignore find_error(ea_t,int); 10 | %ignore find_notype(ea_t,int); 11 | %ignore find_suspop(ea_t,int); 12 | %ignore find_imm(ea_t,int,uval_t); 13 | 14 | %pythoncode %{ 15 | # 16 | # 17 | %} 18 | 19 | %inline %{ 20 | // 21 | // 22 | %} 23 | 24 | %include "search.hpp" 25 | %clear int *opnum; 26 | -------------------------------------------------------------------------------- /swig/segment.i: -------------------------------------------------------------------------------- 1 | // Ignore functions with callbacks 2 | 3 | %ignore enumerate_selectors; 4 | %ignore enumerate_segments_with_selector; 5 | 6 | // Kernel-only 7 | %ignore vset_segm_name; 8 | %ignore get_segm_expr; 9 | %ignore is_debugger_segm; 10 | %ignore is_ephemeral_segm; 11 | %ignore correct_address; 12 | %ignore rebase_program; 13 | %rename (rebase_program) py_rebase_program; 14 | 15 | %template (segment_defsr_array) wrapped_array_t; 16 | 17 | %pywraps_nonnul_argument_prototype( 18 | bool set_segment_translations(ea_t segstart, const eavec_t &transmap), 19 | const eavec_t &transmap); 20 | %{ 21 | // 22 | // 23 | %} 24 | 25 | %extend segment_t 26 | { 27 | ea_t start_ea; 28 | ea_t end_ea; 29 | wrapped_array_t __getDefsr() { 30 | return wrapped_array_t($self->defsr); 31 | } 32 | 33 | %pythoncode { 34 | use64 = is_64bit 35 | defsr = property(__getDefsr) 36 | } 37 | } 38 | 39 | #ifdef __EA64__ 40 | %apply uint64 *OUTPUT { sel_t *sel, ea_t *base }; // getn_selector() 41 | #else 42 | %apply uint *OUTPUT { sel_t *sel, ea_t *base }; // getn_selector() 43 | #endif 44 | 45 | %typemap(check) (sel_t *sel, ea_t *base) { 46 | // getn_selector() check 47 | *($1) = BADSEL; 48 | *($2) = BADADDR; 49 | } 50 | 51 | // 52 | // 53 | 54 | %include "segment.hpp" 55 | 56 | %inline %{ 57 | // 58 | // 59 | %} 60 | -------------------------------------------------------------------------------- /swig/segregs.i: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | %} 4 | 5 | #define R_es 29 6 | #define R_cs 30 7 | #define R_ss 31 8 | #define R_ds 32 9 | #define R_fs 33 10 | #define R_gs 34 11 | 12 | %include "segregs.hpp" 13 | -------------------------------------------------------------------------------- /swig/srclang.i: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | %} 4 | 5 | %ignore srclang_parser_t; 6 | %ignore srclang_parsers_t; 7 | %ignore srclang_parser_obj_t; 8 | %ignore install_srclang_parser; 9 | %ignore remove_srclang_parser; 10 | %ignore select_srclang_parser; 11 | %ignore get_srclang_parser_internal; 12 | %ignore get_current_srclang_parser; 13 | %ignore srclang_parser_visitor_t; 14 | %ignore for_all_srclang_parsers; 15 | %ignore find_parser_kind_t; 16 | %ignore find_srclang_parser; 17 | %ignore find_parser_by_idx; 18 | %ignore find_parser_by_name; 19 | %ignore find_parser_by_srclang; 20 | %ignore init_srclang_parser; 21 | %ignore term_srclang_parser; 22 | 23 | %include "srclang.hpp" 24 | -------------------------------------------------------------------------------- /swig/strlist.i: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | %} 4 | 5 | %ignore strwinsetup_t::setup_strings_window; 6 | %ignore strwinsetup_t::save_config; 7 | %ignore strwinsetup_t::restore_config; 8 | 9 | %extend strwinsetup_t { 10 | 11 | PyObject *_get_strtypes() 12 | { 13 | const bytevec_t &t = $self->strtypes; 14 | size_t n = t.size(); 15 | PyObject *py_t = PyList_New(n); 16 | for ( size_t i = 0, n = t.size(); i < n; ++i ) 17 | PyList_SetItem(py_t, i, PyInt_FromLong(t[i])); 18 | return py_t; 19 | } 20 | 21 | PyObject *_set_strtypes(PyObject *py_t) 22 | { 23 | if ( PySequence_Check(py_t) ) 24 | { 25 | Py_ssize_t n = PySequence_Size(py_t); 26 | bytevec_t t; 27 | t.reserve(n); 28 | for ( size_t i = 0; i < n; ++i ) 29 | { 30 | newref_t pyo(PySequence_GetItem(py_t, i)); 31 | if ( PyLong_Check(pyo.o) ) 32 | { 33 | long stype = PyLong_AsLong(pyo.o); 34 | if ( stype < 0 || stype >= 0x100 ) 35 | { 36 | PyErr_SetString(PyExc_ValueError, "values must be between 0 & 0x100"); 37 | return nullptr; 38 | } 39 | t.push_back(uchar(stype)); 40 | } 41 | else 42 | { 43 | PyErr_SetString(PyExc_ValueError, "expected an integer"); 44 | return nullptr; 45 | } 46 | } 47 | $self->strtypes.swap(t); 48 | } 49 | else 50 | { 51 | PyErr_SetString(PyExc_TypeError, "expected a list"); 52 | return nullptr; 53 | } 54 | Py_RETURN_TRUE; 55 | } 56 | 57 | %pythoncode { 58 | strtypes = property(_get_strtypes, _set_strtypes) 59 | } 60 | } 61 | %ignore strwinsetup_t::strtypes; 62 | 63 | %include "strlist.hpp" 64 | -------------------------------------------------------------------------------- /swig/tryblks.i: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | %} 4 | 5 | %ignore tryblk_t::reserve; 6 | %ignore tryblk_t::cpp() const; 7 | %ignore tryblk_t::seh() const; 8 | 9 | %template(tryblks_t) qvector; 10 | %template(catchvec_t) qvector; 11 | 12 | %include "tryblks.hpp" 13 | -------------------------------------------------------------------------------- /swig/undo.i: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | %} 4 | 5 | %include "typemaps.i" 6 | 7 | // Typemap to convert Python bytes to `const unsigned char*` and `size_t` for create_undo_point 8 | %typemap(in) (const unsigned char *bytes, size_t size) { 9 | Py_ssize_t length; 10 | const char *temp; 11 | if (PyBytes_Check($input)) { 12 | if (PyBytes_AsStringAndSize($input, (char**)&temp, &length) == -1) { 13 | SWIG_fail; 14 | } 15 | } else { 16 | SWIG_exception_fail(SWIG_TypeError, "Expected a bytes object"); 17 | } 18 | 19 | $1 = (const unsigned char *)temp; // Cast to const unsigned char* from const char* 20 | $2 = (size_t)length; 21 | } 22 | 23 | %inline %{ 24 | bool create_undo_point(PyObject *input_bytes) { 25 | const unsigned char *bytes; 26 | size_t size; 27 | if (!PyBytes_Check(input_bytes)) { 28 | PyErr_SetString(PyExc_TypeError, "Expected a bytes object"); 29 | return false; 30 | } 31 | // Perform the conversion from python bytes to unsigned char * 32 | bytes = (const unsigned char *)PyBytes_AsString(input_bytes); 33 | size = (size_t)PyBytes_Size(input_bytes); 34 | 35 | // Call the original C++ function 36 | return ::create_undo_point(bytes, size); 37 | } 38 | %} 39 | 40 | %include "undo.hpp" 41 | -------------------------------------------------------------------------------- /test_pywraps.ini: -------------------------------------------------------------------------------- 1 | READ_NUM 12 2 | READ_NUM 0xFFFF 3 | READ_NUM 0xFFFFFFFF 4 | READ_NUM 0x00000FFFFFFF 5 | READ_NUM 0x0000FFFFFFFF 6 | READ_NUM 0x0000FFFFFFFFFFFF 7 | READ_NUM 0x0000FFFFFFFFFFFF1234 8 | READ_NUM 0x00000000FFFFFFFF 9 | READ_NUM 0x00000000FFFFFFFF1234 10 | READ_NUM 0xFFFFFFFFFFFF0000 11 | READ_NUM 0x1234FFFFFFFFFFFF0000 12 | READ_NUM 0xFFFFFFFF00000000 13 | READ_NUM 0x1234FFFFFFFF00000000 14 | READ_NUM 0xFFFFFFFF0000 15 | READ_NUM 0x1234FFFFFFFF0000 16 | READ_NUM 0xFFFFFFFF00001234 17 | READ_NUM -0xFFFF 18 | READ_NUM -0xFFFFFFFF 19 | READ_NUM -0x00000FFFFFFF 20 | READ_NUM -0x0000FFFFFFFF 21 | READ_NUM -0x0000FFFFFFFFFFFF 22 | READ_NUM -0x0000FFFFFFFFFFFF1234 23 | READ_NUM -0x00000000FFFFFFFF 24 | READ_NUM -0x00000000FFFFFFFF1234 25 | READ_NUM -0xFFFFFFFFFFFF0000 26 | READ_NUM -0x1234FFFFFFFFFFFF0000 27 | READ_NUM -0xFFFFFFFF00000000 28 | READ_NUM -0x1234FFFFFFFF00000000 29 | READ_NUM -0x1234FFFFFFFF0000 30 | READ_NUM -0xFFFFFFFF0000 31 | READ_NUM -0xFFFFFFFF00001234 32 | READ_NUM "Hello" 33 | READ_NUM "None" 34 | READ_NUM True 35 | -------------------------------------------------------------------------------- /tools/docs/templates/config.mako: -------------------------------------------------------------------------------- 1 | <%! 2 | lunr_search = {'fuzziness': 1, 'index_docstrings': True} 3 | %> -------------------------------------------------------------------------------- /tools/docs/templates/credits.mako: -------------------------------------------------------------------------------- 1 |

Copyright (c) 2021 Hex-Rays SA. Terms of use and privacy policy.

2 | -------------------------------------------------------------------------------- /tools/docs/templates/head.mako: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /tools/docs/templates/index.mako: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | <%namespace name="css" file="css.mako" /> 10 | 11 | 12 | 13 | 16 | 17 | 18 |
19 |

IDAPython documentation

20 |
21 |
22 |
23 |

Defined modules:

24 |
    25 | % for mod in modules: 26 |
  • ${mod.name}
  • 27 | % endfor 28 |
29 |
30 | 35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /tools/examples_index_template.md: -------------------------------------------------------------------------------- 1 | [HTML version](http://htmlpreview.github.io/?https://github.com/idapython/src/blob/master/examples/index.html) 2 | 3 | # IDAPython examples 4 | 5 | % for category in sorted(examples): 6 | ## Category: {{category}} 7 | 8 | % for example in sorted(examples[category], key=lambda e: e.name): 9 | #### {{example.name}} 10 |
11 | {{example.summary}} 12 | 13 |
14 | 15 | #### Source code 16 | {{example.path}} 17 | 18 | #### Category 19 | {{example.category}} 20 | 21 | #### Description 22 | {{example.description if example.description else example.summary}} 23 | 24 | % if example.shortcuts: 25 | #### Shortcut{{'s' if len(example.shortcuts) > 1 else ''}} 26 | {{' '.join(example.shortcuts)}} 27 | 28 | % endif 29 | % if example.keywords: 30 | #### Keywords 31 | {{' '.join(example.keywords)}} 32 | 33 | % endif 34 | % if example.imports: 35 | #### Imports 36 | % for imported in example.imports: 37 | * {{imported}} 38 | % endfor 39 | 40 | % endif 41 | % if example.uses: 42 | #### Uses 43 | % for use in example.uses: 44 | * {{use}} 45 | % endfor 46 | 47 | % endif 48 | % if example.see_also: 49 | #### See also 50 | % for see in example.see_also: 51 | * [{{see}}](#{{see}}) 52 | % endfor 53 | 54 | % endif 55 | % if example.author: 56 | #### Author 57 | {{example.author}} 58 | 59 | % endif 60 |
61 | 62 |
63 | 64 | % endfor # examples of a category 65 | % endfor # categories 66 | -------------------------------------------------------------------------------- /tools/gen_examples_index.cfg: -------------------------------------------------------------------------------- 1 | { 2 | "auto-keywords": [ 3 | ["ctxmenu", [r"ida_kernwin\.attach_action_to_popup"]], 4 | ["plugin", [r"ida_idaapi\.plugin_t"]], 5 | ["%(1)s", [r"ida_.*\.(.*_Hooks)"]], 6 | ], 7 | "exclude": [ 8 | "simple_appcall_common" 9 | ], 10 | "link-format": "%(1)s" 11 | } 12 | -------------------------------------------------------------------------------- /tools/genhooks/all_recipes.py: -------------------------------------------------------------------------------- 1 | 2 | import recipe_idphooks 3 | import recipe_idbhooks 4 | import recipe_dbghooks 5 | import recipe_uihooks 6 | import recipe_viewhooks 7 | import recipe_hexrays 8 | 9 | # filename 10 | # enum name 11 | # discard enum names with prefixes 12 | # discard docs with prefixes 13 | # remove prefixes from enum value names 14 | # module with recipes 15 | 16 | hooks = { 17 | "IDP_Hooks" : ( 18 | "structprocessor__t.xml", 19 | "event_t", 20 | [], 21 | None, 22 | [], 23 | recipe_idphooks 24 | ), 25 | "IDB_Hooks" : ( 26 | "namespaceidb__event.xml", 27 | "event_code_t", 28 | [], 29 | None, 30 | [], 31 | recipe_idbhooks 32 | ), 33 | "DBG_Hooks" : ( 34 | "dbg_8hpp.xml", 35 | "dbg_notification_t", 36 | [], 37 | None, 38 | [], 39 | recipe_dbghooks 40 | ), 41 | "UI_Hooks" : ( 42 | "kernwin_8hpp.xml", 43 | "ui_notification_t", 44 | ["ui_dbg_", "ui_obsolete"], 45 | "ui:", 46 | ["ui_"], 47 | recipe_uihooks 48 | ), 49 | "View_Hooks" : ( 50 | "kernwin_8hpp.xml", 51 | "view_notification_t", 52 | [], 53 | None, 54 | [], 55 | recipe_viewhooks 56 | ), 57 | "Hexrays_Hooks" : ( 58 | "hexrays_8hpp.xml", 59 | "hexrays_event_t", 60 | [], 61 | None, 62 | ["hxe_", "lxe_"], 63 | recipe_hexrays 64 | ) 65 | } 66 | -------------------------------------------------------------------------------- /tools/genhooks/gendoxycfg.py: -------------------------------------------------------------------------------- 1 | 2 | import string 3 | 4 | from argparse import ArgumentParser 5 | p = ArgumentParser() 6 | p.add_argument("-i", "--input", required=True, dest="input", help="Input file") 7 | p.add_argument("-o", "--output", required=True, dest="output", help="Output file") 8 | p.add_argument("-I", "--includes", required=True) 9 | args = p.parse_args() 10 | 11 | with open(args.input) as fin: 12 | with open(args.output, "w") as fout: 13 | template = string.Template(fin.read()) 14 | kvps = { 15 | "INCLUDES" : " ".join(args.includes.split(",")), 16 | } 17 | fout.write(template.safe_substitute(kvps)) 18 | -------------------------------------------------------------------------------- /tools/genhooks/recipe_hexrays.py: -------------------------------------------------------------------------------- 1 | 2 | recipe = { 3 | "stkpnts" : { 4 | "params" : { 5 | "stkpnts" : { "rename" : "_sps", }, 6 | }, 7 | }, 8 | "create_hint" : { 9 | "params" : { 10 | "hint" : { "suppress_for_call" : True, }, 11 | "important_lines" : { "suppress_for_call" : True, }, 12 | }, 13 | "return" : { 14 | "type" : "PyObject *", 15 | "retexpr" : "Py_RETURN_NONE", 16 | "convertor" : "Hexrays_Hooks::handle_create_hint_output", 17 | "convertor_pass_args" : True, 18 | } 19 | }, 20 | "build_callinfo" : { 21 | "params" : { 22 | "callinfo" : { "suppress_for_call" : True, }, 23 | }, 24 | "return" : { 25 | "type" : "PyObject *", 26 | "retexpr" : "Py_RETURN_NONE", 27 | "convertor" : "Hexrays_Hooks::handle_build_callinfo_output", 28 | "convertor_pass_args" : True, 29 | } 30 | }, 31 | } 32 | 33 | default_rtype = "int" 34 | -------------------------------------------------------------------------------- /tools/genhooks/recipe_idbhooks.py: -------------------------------------------------------------------------------- 1 | 2 | recipe = { 3 | "enum_const_created" : { 4 | "method_name" : "enum_member_created", 5 | "add_params" : [ 6 | { "name" : "id", "type" : "enum_t" }, 7 | { "name" : "cid", "type" : "const_t" }, 8 | ], 9 | }, 10 | "enum_const_deleted" : { 11 | "method_name" : "enum_member_deleted", 12 | "add_params" : [ 13 | { "name" : "id", "type" : "enum_t" }, 14 | { "name" : "cid", "type" : "const_t" }, 15 | ], 16 | }, 17 | } 18 | 19 | default_rtype = "void" 20 | -------------------------------------------------------------------------------- /tools/genhooks/recipe_viewhooks.py: -------------------------------------------------------------------------------- 1 | 2 | recipe = { 3 | } 4 | 5 | default_rtype = "void" 6 | -------------------------------------------------------------------------------- /tools/genidaapi.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | import sys 4 | import string 5 | from argparse import ArgumentParser 6 | 7 | parser = ArgumentParser() 8 | parser.add_argument("-i", "--input", required=True) 9 | parser.add_argument("-o", "--output", required=True) 10 | parser.add_argument("-m", "--modules", required=True) 11 | args = parser.parse_args() 12 | 13 | # Hack to force ida_idaapi to be loaded as first element 14 | mods = args.modules.split(",") 15 | mods.insert(0, mods.pop(mods.index("idaapi"))) 16 | 17 | with open(args.input) as fin: 18 | with open(args.output, "w") as fout: 19 | template = string.Template(fin.read()) 20 | kvps = { 21 | "MODULES" : ",".join(mods), 22 | "IMPORTS" : "\n".join([(f"from ida_{mod} import *") for mod in mods ]) 23 | } 24 | fout.write(template.substitute(kvps)) 25 | -------------------------------------------------------------------------------- /tools/inject_pydoc/bytes.py: -------------------------------------------------------------------------------- 1 | { 2 | "op_stroff" : { 3 | "+example" : 4 | """ 5 | ins = ida_ua.insn_t() 6 | if ida_ua.decode_insn(ins, some_address): 7 | path_len = 1 8 | path = ida_pro.tid_array(path_len) 9 | path[0] = ida_typeinf.get_named_type_tid("my_stucture_t") 10 | ida_bytes.op_stroff(ins, 0, path.cast(), path_len, 0) 11 | """ 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tools/inject_pydoc/idp.py: -------------------------------------------------------------------------------- 1 | { 2 | "ev_get_bg_color" : { 3 | "repl_text" : ("(self, color, ea) -> int", "(self, ea) -> int or None"), 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tools/inject_pydoc_cases.txt: -------------------------------------------------------------------------------- 1 | 2 | # Individual exceptions to the general processing in "inject_pydoc.py". 3 | 4 | { 5 | "typeinf.til_t.base" : [ 6 | { 7 | "doxy-kind" : "variable" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /tools/patch_codegen/bytes.py: -------------------------------------------------------------------------------- 1 | { 2 | "next_that" : [ 3 | ("nullptr_result_on_py_error", None), 4 | ], 5 | "prev_that" : [ 6 | ("nullptr_result_on_py_error", None), 7 | ], 8 | } 9 | -------------------------------------------------------------------------------- /tools/patch_codegen/dbg.py: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "SwigDirector_DBG_Hooks::SwigDirector_DBG_Hooks" : [ 4 | ("maybe_collect_director_fixed_method_set", None), 5 | ], 6 | } 7 | -------------------------------------------------------------------------------- /tools/patch_codegen/dirtree.py: -------------------------------------------------------------------------------- 1 | { 2 | "SwigDirector_dirspec_t::get_name" : [ 3 | ("repl_text", ( 4 | "int swig_res = SWIG_AsVal_bool(result, &swig_val);", 5 | ("int swig_res = PyUnicode_Check(result) && (out == nullptr || PyUnicode_as_qstring(out, result));", 6 | " swig_val = static_cast(swig_res);"))), 7 | ("director_method_call_arity_cap", ( 8 | True, # add GIL lock 9 | "get_name", 10 | "(method ,(PyObject *)obj0,(__argcnt < 2 ? nullptr : (PyObject *)obj1), nullptr)", 11 | "(swig_get_self(), (PyObject *) swig_method_name ,(PyObject *)obj0,(__argcnt < 3 ? nullptr : (PyObject *)obj1), nullptr)", 12 | )), 13 | ("spontaneous_callback_call", ( 14 | False, # add GIL lock 15 | None, # try anchor 16 | None, # catch anchor 17 | )), 18 | ], 19 | "SwigDirector_dirspec_t::get_inode" : [ 20 | ("spontaneous_callback_call", None) 21 | ], 22 | "SwigDirector_dirspec_t::get_attrs" : [ 23 | ("spontaneous_callback_call", None) 24 | ], 25 | "SwigDirector_dirspec_t::rename_inode" : [ 26 | ("spontaneous_callback_call", None) 27 | ], 28 | "SwigDirector_dirspec_t::unlink_inode" : [ 29 | ("spontaneous_callback_call", ( 30 | True, # add GIL lock 31 | " swig::SwigVar_PyObject obj0;", # try anchor 32 | "}" # catch anchor 33 | )) 34 | ], 35 | } 36 | 37 | -------------------------------------------------------------------------------- /tools/patch_codegen/diskio.py: -------------------------------------------------------------------------------- 1 | { 2 | "SwigDirector_ioports_fallback_t::handle" : [ 3 | ("repl_text", ( 4 | "int swig_res = SWIG_AsVal_bool(result, &swig_val);", 5 | ( 6 | "const bool is_error = PyUnicode_Check(result) != 0;", 7 | " int swig_res = is_error || result == Py_None;", 8 | " if ( is_error )", 9 | " PyUnicode_as_qstring(errbuf, result);", 10 | " swig_val = !is_error;", 11 | ), 12 | )), 13 | ], 14 | 15 | "SwigDirector_choose_ioport_parser_t::parse" : [ 16 | ("repl_text", ( 17 | "int swig_res = SWIG_AsVal_bool(result, &swig_val);", 18 | ("""const bool is_proper_tuple = PyTuple_Check(result) && PyTuple_Size(result) == 2; 19 | const bool is_item0_bool = is_proper_tuple && PyBool_Check(PyTuple_GetItem(result, 0)); 20 | const bool is_success = is_proper_tuple && is_item0_bool && PyTuple_GetItem(result, 0) == Py_True; 21 | const bool is_item1_str = is_proper_tuple && PyUnicode_Check(PyTuple_GetItem(result, 1)); 22 | const bool well_formed = is_proper_tuple && is_item0_bool && ((is_success && is_item1_str) || !is_success); 23 | int swig_res = well_formed; 24 | if ( well_formed ) 25 | { 26 | if ( is_item1_str ) 27 | PyUnicode_as_qstring(param, PyTuple_GetItem(result, 1)); 28 | else 29 | param->qclear(); 30 | } 31 | swig_val = well_formed ? is_success : false; 32 | """))) 33 | ], 34 | } 35 | -------------------------------------------------------------------------------- /tools/patch_codegen/expr.py: -------------------------------------------------------------------------------- 1 | { 2 | "new_idc_value_t" : [ 3 | ("repl_text", ( 4 | "PyObject *argv[2];", 5 | "PyObject *argv[2] = {0, 0};")), 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /tools/patch_codegen/fpro.py: -------------------------------------------------------------------------------- 1 | { 2 | "new_qfile_t" : [ 3 | ("repl_text", ( 4 | "PyObject *argv[2];", 5 | "PyObject *argv[2] = {0, 0};")), 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /tools/patch_codegen/funcs.py: -------------------------------------------------------------------------------- 1 | { 2 | "func_item_iterator_t___next__" : [ 3 | ("nullptr_result_on_py_error", None), 4 | ], 5 | "func_item_iterator_t_prev" : [ 6 | ("nullptr_result_on_py_error", None), 7 | ], 8 | "func_item_iterator_t_succ" : [ 9 | ("nullptr_result_on_py_error", None), 10 | ], 11 | } 12 | 13 | 14 | -------------------------------------------------------------------------------- /tools/patch_codegen/graph.py: -------------------------------------------------------------------------------- 1 | { 2 | "SwigDirector_drawable_graph_t::nrect" : [ 3 | ("repl_text", ("return", "qnotused(c_result); qnotused(n); // return")), 4 | ], 5 | "SwigDirector_drawable_graph_t::get_edge" : [ 6 | ("repl_text", ("return", "qnotused(c_result); qnotused(e); // return")), 7 | ], 8 | "SwigDirector_drawable_graph_t::clone" : [ 9 | ("repl_text", ("return", "qnotused(c_result); // return")), 10 | ], 11 | "SwigDirector_interactive_graph_t::get_edge" : [ 12 | ("repl_text", ("return", "qnotused(c_result); qnotused(e); // return")), 13 | ], 14 | "SwigDirector_interactive_graph_t::clone" : [ 15 | ("repl_text", ("return", "qnotused(c_result); // return")), 16 | ], 17 | } 18 | 19 | -------------------------------------------------------------------------------- /tools/patch_codegen/hexrays.py: -------------------------------------------------------------------------------- 1 | { 2 | "SwigDirector_Hexrays_Hooks::SwigDirector_Hexrays_Hooks" : [ 3 | ("maybe_collect_director_fixed_method_set", None), 4 | ], 5 | 6 | "SwigDirector_microcode_filter_t::match" : [ 7 | ("spontaneous_callback_call", None) 8 | ], 9 | "SwigDirector_microcode_filter_t::apply" : [ 10 | ("spontaneous_callback_call", None) 11 | ], 12 | "SwigDirector_udc_filter_t::match" : [ 13 | ("spontaneous_callback_call", None) 14 | ], 15 | "SwigDirector_optinsn_t::func" : [ 16 | ("director_method_call_arity_cap", ( 17 | True, # add GIL lock 18 | "func", 19 | "(method ,(PyObject *)obj0,(PyObject *)obj1,(__argcnt < 3 ? nullptr : (PyObject *)obj2), nullptr)", 20 | "(swig_get_self(), (PyObject *) swig_method_name ,(PyObject *)obj0,(PyObject *)obj1,(__argcnt < 4 ? nullptr : (PyObject *)obj2), nullptr)", 21 | )), 22 | ("spontaneous_callback_call", ( 23 | False, # add GIL lock 24 | None, # try anchor 25 | None # catch anchor 26 | )), 27 | ], 28 | "SwigDirector_optblock_t::func" : [ 29 | ("spontaneous_callback_call", None) 30 | ], 31 | "new_mba_ranges_t" : [ 32 | ("repl_text", ( 33 | "PyObject *argv[2];", 34 | "PyObject *argv[2] = {0, 0};")), 35 | ], 36 | "get_temp_regs" : [ 37 | ("repl_text", ( 38 | "PyObject *argv[2];", 39 | "PyObject *argv[2] = {0, 0}; qnotused(argv);")), 40 | ], 41 | "new_valrng_t" : [ 42 | ("repl_text", ( 43 | "PyObject *argv[2];", 44 | "PyObject *argv[2] = {0, 0};")), 45 | ], 46 | } 47 | -------------------------------------------------------------------------------- /tools/patch_codegen/hexrays_h.py: -------------------------------------------------------------------------------- 1 | { 2 | } 3 | -------------------------------------------------------------------------------- /tools/patch_codegen/ida_hexrays.py: -------------------------------------------------------------------------------- 1 | { 2 | "repl_line" : [ 3 | ("class casm_t(ida_pro.uintvec_t):", "class casm_t(ida_pro.eavec_t):"), 4 | ("class casm_t(ida_pro.uint64vec_t):", "class casm_t(ida_pro.eavec_t):"), 5 | ], 6 | } 7 | -------------------------------------------------------------------------------- /tools/patch_codegen/lines.py: -------------------------------------------------------------------------------- 1 | { 2 | "SwigDirector_user_defined_prefix_t::get_user_defined_prefix" : [ 3 | ("spontaneous_callback_call", ( 4 | True, # add GIL lock 5 | " swig::SwigVar_PyObject obj0;", # try anchor 6 | "}" # catch anchor 7 | )), 8 | ], 9 | } 10 | -------------------------------------------------------------------------------- /tools/patch_codegen/merge.py: -------------------------------------------------------------------------------- 1 | { 2 | "SwigDirector_merge_node_helper_t::print_entry_name" : [ 3 | ("spontaneous_callback_call", None) 4 | ], 5 | "SwigDirector_merge_node_helper_t::print_entry_details" : [ 6 | ("spontaneous_callback_call", ( 7 | True, # add GIL lock 8 | " swig::SwigVar_PyObject obj0;", # try anchor 9 | "}" # catch anchor 10 | )), 11 | ], 12 | "SwigDirector_merge_node_helper_t::get_column_headers" : [ 13 | ("spontaneous_callback_call", ( 14 | True, # add GIL lock 15 | " swig::SwigVar_PyObject obj0;", # try anchor 16 | "}" # catch anchor 17 | )), 18 | ], 19 | "SwigDirector_merge_node_helper_t::is_mergeable" : [ 20 | ("spontaneous_callback_call", None) 21 | ], 22 | "SwigDirector_merge_node_helper_t::get_netnode" : [ 23 | ("spontaneous_callback_call", ( 24 | True, # add GIL lock 25 | " netnode c_result;", # try anchor 26 | None # catch anchor 27 | )), 28 | ], 29 | "SwigDirector_merge_node_helper_t::map_scalar" : [ 30 | ("spontaneous_callback_call", ( 31 | True, # add GIL lock 32 | " swig::SwigVar_PyObject obj0;", # try anchor 33 | "}" # catch anchor 34 | )), 35 | ], 36 | "SwigDirector_merge_node_helper_t::map_string" : [ 37 | ("spontaneous_callback_call", ( 38 | True, # add GIL lock 39 | " swig::SwigVar_PyObject obj0;", # try anchor 40 | "}" # catch anchor 41 | )), 42 | ], 43 | # ignored, see merge.i 44 | # "SwigDirector_merge_node_helper_t::map_value" : 45 | "SwigDirector_merge_node_helper_t::refresh" : [ 46 | ("spontaneous_callback_call", ( 47 | True, # add GIL lock 48 | " swig::SwigVar_PyObject obj0;", # try anchor 49 | "}" # catch anchor 50 | )), 51 | ], 52 | # ignored, see merge.i 53 | # "SwigDirector_merge_node_helper_t::get_log_name" : 54 | } 55 | -------------------------------------------------------------------------------- /tools/patch_codegen/nalt.py: -------------------------------------------------------------------------------- 1 | { 2 | "__additional_thread_unsafe__" : 3 | [ 4 | "validate_idb_names", 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /tools/patch_codegen/pro.py: -------------------------------------------------------------------------------- 1 | { 2 | "qexit" : [ 3 | ("repl_text", ("resultobj = SWIG_Py_Void();", " // resultobj = SWIG_Py_Void();")), 4 | ("repl_text", ("return resultobj;", "qnotused(resultobj); // return resultobj;")), 5 | ], 6 | } 7 | -------------------------------------------------------------------------------- /tools/patch_codegen/typeinf.py: -------------------------------------------------------------------------------- 1 | { 2 | "Swig_var_idati_set" : [ 3 | ("repl_text" , ( 4 | "idati = reinterpret_cast< til_t * >(argp);", 5 | "// idati = reinterpret_cast< til_t * >(argp);")), 6 | ], 7 | "Swig_var_idati_get" : [ 8 | ("repl_text" , ("SWIG_as_voidptr(idati)", "SWIG_as_voidptr(/*idati*/ get_idati())")), 9 | ], 10 | "__additional_requires_idb__" : [ 11 | "idc_parse_decl", 12 | "py_calc_type_size", 13 | "py_apply_type", 14 | "py_get_arg_addrs", 15 | "py_unpack_object_from_idb", 16 | "py_unpack_object_from_bv", 17 | "py_pack_object_to_idb", 18 | "py_pack_object_to_bv", 19 | "idc_parse_types", 20 | "py_idc_get_type_raw", 21 | "py_idc_get_local_type_raw", 22 | "idc_guess_type", 23 | "idc_get_type", 24 | "idc_set_local_type", 25 | "idc_get_local_type", 26 | "idc_print_type", 27 | "idc_get_local_type_name", 28 | "py_get_named_type", 29 | "py_get_named_type64", 30 | "py_print_decls", 31 | "py_load_til", 32 | "py_load_til_header", 33 | "py_remove_tinfo_pointer", 34 | "py_get_numbered_type", 35 | ], 36 | } 37 | -------------------------------------------------------------------------------- /tools/patch_codegen/typeinf_batch.py: -------------------------------------------------------------------------------- 1 | { 2 | "requires_idb" : [ 3 | ".*", 4 | "-is_type_.*", 5 | "-get_base_type", 6 | "-get_type_flags", 7 | "-get_full_type", 8 | "-is_typeid_last", 9 | "-is_tah_byte", 10 | "-is_sdacl_byte", 11 | "-get_cc", 12 | "-is_.*_cc", 13 | "-convert_pt_flags_to_hti", 14 | ], 15 | } 16 | -------------------------------------------------------------------------------- /tools/patch_h_codegen.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | import os 4 | from argparse import ArgumentParser 5 | 6 | parser = ArgumentParser(description='Patch some header code generation, so it builds') 7 | parser.add_argument("-f", "--file", required=True) 8 | parser.add_argument("-p", "--patches", required=True) 9 | parser.add_argument("-v", "--verbose", default=False, action="store_true") 10 | parser.add_argument("-m", "--module", required=True) 11 | args = parser.parse_args() 12 | 13 | if os.path.isfile(args.patches): 14 | with open(args.file) as fin: 15 | lines = fin.readlines() 16 | 17 | patches = {} 18 | with open(args.patches) as fin: 19 | patches = eval(fin.read()) 20 | 21 | all_lines = [] 22 | for l in lines: 23 | l = l.replace(", ...arg0)", ", ...)") 24 | l = l.replace(",...arg0)", ",...)") 25 | all_lines.append(l) 26 | 27 | import tempfile 28 | temp = tempfile.NamedTemporaryFile(mode="w", delete=False) 29 | temp.writelines(all_lines) 30 | temp.close() 31 | 32 | import shutil 33 | shutil.move(temp.name, args.file) 34 | -------------------------------------------------------------------------------- /tools/patch_python_codegen.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | import os 4 | 5 | from argparse import ArgumentParser 6 | 7 | parser = ArgumentParser(description='Patch some Python code generation, so it builds') 8 | parser.add_argument("-f", "--file", required=True) 9 | parser.add_argument("-p", "--patches", required=True) 10 | parser.add_argument("-v", "--verbose", default=False, action="store_true") 11 | parser.add_argument("-m", "--module", required=True) 12 | args = parser.parse_args() 13 | 14 | if os.path.isfile(args.patches): 15 | with open(args.file) as fin: 16 | # strip newlines for easier matching 17 | lines = map(str.rstrip, fin.readlines()) 18 | 19 | patches = {} 20 | with open(args.patches) as fin: 21 | patches = eval(fin.read()) 22 | 23 | all_lines = [] 24 | for l in lines: 25 | for patch_kind, patch_data in patches.items(): 26 | if patch_kind == "repl_line": 27 | for from_, to in patch_data: 28 | if l == from_: 29 | l = to 30 | all_lines.append(l) 31 | 32 | import tempfile 33 | temp = tempfile.NamedTemporaryFile(mode="w", delete=False) 34 | # since we had stripped newlines, need to add them back explicitly 35 | temp.write("\n".join(all_lines)) 36 | temp.close() 37 | 38 | import shutil 39 | shutil.move(temp.name, args.file) 40 | -------------------------------------------------------------------------------- /tools/pydoc_data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HexRaysSA/IDAPython/bd1c5927f0ad44048fcd9cc42a9a743504e6c7a0/tools/pydoc_data/__init__.py -------------------------------------------------------------------------------- /tools/pydoc_data/_pydoc.css: -------------------------------------------------------------------------------- 1 | /* 2 | CSS file for pydoc. 3 | 4 | Contents of this file are subject to change without notice. 5 | 6 | */ 7 | -------------------------------------------------------------------------------- /tools/split_hexrays_templates.py: -------------------------------------------------------------------------------- 1 | 2 | from argparse import ArgumentParser 3 | p = ArgumentParser() 4 | p.add_argument("-i", "--input", required=True) 5 | p.add_argument("--out-templates", required=True) 6 | p.add_argument("--out-body", required=True) 7 | args = p.parse_args() 8 | 9 | templates = [] 10 | body = [] 11 | 12 | with open(args.input) as fin: 13 | lines = fin.readlines() 14 | 15 | in_template=False 16 | for line in lines: 17 | if not in_template: 18 | if line.startswith("template <"): 19 | in_template=True 20 | else: 21 | body.append(line) 22 | if in_template: 23 | templates.append(line) 24 | if line.startswith("};"): 25 | in_template = False 26 | 27 | with open(args.out_templates, "w") as fout: 28 | fout.write("".join(templates)) 29 | with open(args.out_body, "w") as fout: 30 | fout.write("".join(body)) 31 | -------------------------------------------------------------------------------- /tools/typemaps-supplement/pymacros.swg: -------------------------------------------------------------------------------- 1 | 2 | // We'll take advantage of the fact that SWiG's 'python.swg' includes 3 | // an "unqualified" 'pymacros.swg', for us to override a SWiG define 4 | // that will be used for generating exception text (and which I have 5 | // found no other way to redefine). Then, we'll include the real 6 | // 'pymacros.swg' file, as if nothing happened. 7 | #define SWIG_DirOutFail(code, msg) Swig::DirectorTypeMismatchException::raise(SWIG_ErrorType(code), msg " in method '$symname'") 8 | 9 | %include 10 | --------------------------------------------------------------------------------