diff --git a/examples/uihooks/prevent_jump.py b/examples/uihooks/prevent_jump.py new file mode 100644 index 0000000..dca16d7 --- /dev/null +++ b/examples/uihooks/prevent_jump.py @@ -0,0 +1,18 @@ +""" +This example shows how to use ida_kernwin.UI_Hooks, to respond to a +command instead of the action that would otherwise do it. +""" + +import ida_kernwin + +class prevent_jump_t(ida_kernwin.UI_Hooks): + def preprocess_action(self, action_name): + if action_name == "JumpEnter": + print("Inhibiting 'jump'!") + return 1 + return 0 + +phh = prevent_jump_t() +if phh.hook(): + print("From now on, pressing will prevent IDA from jumping. "\ + +"Please type 'phh.unhook()' to revert to the normal behavior.") diff --git a/examples/widgets/forms/askusingform.py b/examples/widgets/forms/askusingform.py index 644cecf..17eba92 100644 --- a/examples/widgets/forms/askusingform.py +++ b/examples/widgets/forms/askusingform.py @@ -3,37 +3,45 @@ from __future__ import print_function # This is an example illustrating how to use the Form class # (c) Hex-Rays # -from ida_kernwin import Form, Choose, ask_str +import ida_kernwin # -------------------------------------------------------------------------- -class TestEmbeddedChooserClass(Choose): - """ - A simple chooser to be used as an embedded chooser - """ - def __init__(self, title, nb = 5, flags = 0): - Choose.__init__(self, - title, - [ ["Address", 10], ["Name", 30] ], - flags=flags, - embedded=True, width=30, height=6) - self.items = [ [str(x), "func_%04d" % x] - for x in range(nb + 1) ] - self.icon = 5 +class busy_form_t(ida_kernwin.Form): - def OnGetLine(self, n): - print("getline %d" % n) - return self.items[n] + class test_chooser_t(ida_kernwin.Choose): + """ + A simple chooser to be used as an embedded chooser + """ + def __init__(self, title, nb=5, flags=ida_kernwin.Choose.CH_MULTI): + ida_kernwin.Choose.__init__( + self, + title, + [ + ["Address", 10], + ["Name", 30] + ], + flags=flags, + embedded=True, + width=30, + height=6) + self.items = [ [str(x), "func_%04d" % x] for x in range(nb + 1) ] + self.icon = 5 - def OnGetSize(self): - n = len(self.items) - print("getsize -> %d" % n) - return n + def OnGetLine(self, n): + print("getline %d" % n) + return self.items[n] + + def OnGetSize(self): + n = len(self.items) + print("getsize -> %d" % n) + return n -# -------------------------------------------------------------------------- -class MyForm(Form): def __init__(self): self.invert = False - Form.__init__(self, r"""STARTITEM {id:rNormal} + F = ida_kernwin.Form + F.__init__( + self, + r"""STARTITEM {id:rNormal} BUTTON YES* Yeah BUTTON NO Nope BUTTON CANCEL Nevermind @@ -66,37 +74,34 @@ Button test: <##Button1:{iButton1}> <##Button2:{iButton2}> The end! """, { - 'cStr1': Form.StringLabel("Hello"), - 'cHtml1': Form.StringLabel("Is this red?", tp=Form.FT_HTML_LABEL), - 'cAddr1': Form.NumericLabel(0x401000, Form.FT_ADDR), - 'cVal1' : Form.NumericLabel(99, Form.FT_HEX), - 'iStr1': Form.StringInput(), - 'iColor1': Form.ColorInput(), - 'iFileOpen': Form.FileInput(open=True), - 'iFileSave': Form.FileInput(save=True), - 'iDir': Form.DirInput(), - 'iType': Form.StringInput(tp=Form.FT_TYPE), - 'iSegment': Form.NumericInput(tp=Form.FT_SEG), - 'iRawHex': Form.NumericInput(tp=Form.FT_RAWHEX), - 'iAddr': Form.NumericInput(tp=Form.FT_ADDR), - 'iChar': Form.NumericInput(tp=Form.FT_CHAR), - 'iButton1': Form.ButtonInput(self.OnButton1), - 'iButton2': Form.ButtonInput(self.OnButton2), - 'cGroup1': Form.ChkGroupControl(("rNormal", "rError", "rWarnings")), - 'cGroup2': Form.RadGroupControl(("rRed", "rGreen", "rBlue")), - 'FormChangeCb': Form.FormChangeCb(self.OnFormChange), - 'cEChooser' : Form.EmbeddedChooserControl(TestEmbeddedChooserClass("E1", flags=Choose.CH_MULTI)) + 'cStr1': F.StringLabel("Hello"), + 'cHtml1': F.StringLabel("Is this red?", tp=F.FT_HTML_LABEL), + 'cAddr1': F.NumericLabel(0x401000, F.FT_ADDR), + 'cVal1' : F.NumericLabel(99, F.FT_HEX), + 'iStr1': F.StringInput(), + 'iColor1': F.ColorInput(), + 'iFileOpen': F.FileInput(open=True), + 'iFileSave': F.FileInput(save=True), + 'iDir': F.DirInput(), + 'iType': F.StringInput(tp=F.FT_TYPE), + 'iSegment': F.NumericInput(tp=F.FT_SEG), + 'iRawHex': F.NumericInput(tp=F.FT_RAWHEX), + 'iAddr': F.NumericInput(tp=F.FT_ADDR), + 'iChar': F.NumericInput(tp=F.FT_CHAR), + 'iButton1': F.ButtonInput(self.OnButton1), + 'iButton2': F.ButtonInput(self.OnButton2), + 'cGroup1': F.ChkGroupControl(("rNormal", "rError", "rWarnings")), + 'cGroup2': F.RadGroupControl(("rRed", "rGreen", "rBlue")), + 'FormChangeCb': F.FormChangeCb(self.OnFormChange), + 'cEChooser' : F.EmbeddedChooserControl(busy_form_t.test_chooser_t("E1")) }) - def OnButton1(self, code=0): print("Button1 pressed") - def OnButton2(self, code=0): print("Button2 pressed") - def OnFormChange(self, fid): if fid == self.iButton1.id: print("Button1 fchg;inv=%s" % self.invert) @@ -123,113 +128,70 @@ The end! print(">>fid:%d" % fid) return 1 + @staticmethod + def compile_and_fiddle_with_fields(): + f = busy_form_t() + f, args = f.Compile() + print(args[0]) + print(args[1:]) + f.rNormal.checked = True + f.rWarnings.checked = True + print(hex(f.cGroup1.value)) + f.rGreen.selected = True + print(f.cGroup2.value) + print("Title: '%s'" % f.title) + + f.Free() + + @staticmethod + def test(): + f = busy_form_t() + + # Compile (in order to populate the controls) + f.Compile() + + f.iColor1.value = 0x5bffff + f.iDir.value = os.getcwd() + f.iChar.value = ord("a") + f.rNormal.checked = True + f.rWarnings.checked = True + f.rGreen.selected = True + f.iStr1.value = "Hello" + f.iFileSave.value = "*.*" + f.iFileOpen.value = "*.*" + + # Execute the form + ok = f.Execute() + print("r=%d" % ok) + if ok == 1: + print("f.str1=%s" % f.iStr1.value) + print("f.color1=%x" % f.iColor1.value) + print("f.openfile=%s" % f.iFileOpen.value) + print("f.savefile=%s" % f.iFileSave.value) + print("f.dir=%s" % f.iDir.value) + print("f.type=%s" % f.iType.value) + print("f.seg=%s" % f.iSegment.value) + print("f.rawhex=%x" % f.iRawHex.value) + print("f.char=%x" % f.iChar.value) + print("f.addr=%x" % f.iAddr.value) + print("f.cGroup1=%x" % f.cGroup1.value) + print("f.cGroup2=%x" % f.cGroup2.value) + sel = f.cEChooser.selection + if sel is None: + print("No selection") + else: + print("Selection: %s" % sel) + + # Dispose the form + f.Free() # -------------------------------------------------------------------------- -def stdalone_main(): - f = MyForm() - f, args = f.Compile() - print(args[0]) - print(args[1:]) - f.rNormal.checked = True - f.rWarnings.checked = True - print(hex(f.cGroup1.value)) - - f.rGreen.selected = True - print(f.cGroup2.value) - print("Title: '%s'" % f.title) - - f.Free() - -# -------------------------------------------------------------------------- -def ida_main(): - # Create form - global f - f = MyForm() - - # Compile (in order to populate the controls) - f.Compile() - - f.iColor1.value = 0x5bffff - f.iDir.value = os.getcwd() - f.iChar.value = ord("a") - f.rNormal.checked = True - f.rWarnings.checked = True - f.rGreen.selected = True - f.iStr1.value = "Hello" - f.iFileSave.value = "*.*" - f.iFileOpen.value = "*.*" - # Execute the form - ok = f.Execute() - print("r=%d" % ok) - if ok == 1: - print("f.str1=%s" % f.iStr1.value) - print("f.color1=%x" % f.iColor1.value) - print("f.openfile=%s" % f.iFileOpen.value) - print("f.savefile=%s" % f.iFileSave.value) - print("f.dir=%s" % f.iDir.value) - print("f.type=%s" % f.iType.value) - print("f.seg=%s" % f.iSegment.value) - print("f.rawhex=%x" % f.iRawHex.value) - print("f.char=%x" % f.iChar.value) - print("f.addr=%x" % f.iAddr.value) - print("f.cGroup1=%x" % f.cGroup1.value) - print("f.cGroup2=%x" % f.cGroup2.value) - sel = f.cEChooser.selection - if sel is None: - print("No selection") - else: - print("Selection: %s" % sel) - - # Dispose the form - f.Free() - -# -------------------------------------------------------------------------- -def ida_main_legacy(): - # Here we simply show how to use the old style form format using Python - - # Sample form from kernwin.hpp - s = """Sample dialog box - - -This is sample dialog box for %A -using address %$ - -<~E~nter value:N::18::> -""" - - # Use either StringArgument or NumericArgument to pass values to the function - num = Form.NumericArgument('N', value=123) - ok = idaapi.ask_form(s, - Form.StringArgument("PyAskform").arg, - Form.NumericArgument('$', 0x401000).arg, - num.arg) - if ok == 1: - print("You entered: %x" % num.value) - -# -------------------------------------------------------------------------- -def test_multilinetext_legacy(): - # Here we text the multi line text control in legacy mode - - # Sample form from kernwin.hpp - s = """Sample dialog box - -This is sample dialog box - -""" - # Use either StringArgument or NumericArgument to pass values to the function - ti = textctrl_info_t("Some initial value") - ok = idaapi.ask_form(s, pointer(c_void_p.from_address(ti.clink_ptr))) - if ok == 1: - print("You entered: %s" % ti.text) - - del ti - -# -------------------------------------------------------------------------- -class MyForm2(Form): - """Simple Form to test multilinetext and combo box controls""" +class multiline_text_t(ida_kernwin.Form): + """Simple Form to test multilinetext""" def __init__(self): - Form.__init__(self, r"""STARTITEM 0 + F = ida_kernwin.Form + F.__init__(self, r"""STARTITEM 0 BUTTON YES* Yeah BUTTON NO Nope BUTTON CANCEL NONE @@ -238,11 +200,10 @@ Form Test {FormChangeCb} """, { - 'txtMultiLineText': Form.MultiLineTextControl(text="Hello"), - 'FormChangeCb': Form.FormChangeCb(self.OnFormChange), + 'txtMultiLineText': F.MultiLineTextControl(text="Hello"), + 'FormChangeCb': F.FormChangeCb(self.OnFormChange), }) - def OnFormChange(self, fid): if fid == self.txtMultiLineText.id: pass @@ -253,30 +214,29 @@ Form Test print(">>fid:%d" % fid) return 1 -# -------------------------------------------------------------------------- -def test_multilinetext(execute=True): - """Test the multilinetext and combobox controls""" - f = MyForm2() - f, args = f.Compile() - if execute: - ok = f.Execute() - else: - print(args[0]) - print(args[1:]) - ok = 0 + @staticmethod + def test(execute=True): + f = multiline_text_t() + f, args = f.Compile() + if execute: + ok = f.Execute() + else: + print(args[0]) + print(args[1:]) + ok = 0 + if ok == 1: + assert f.txtMultiLineText.text == f.txtMultiLineText.value + print(f.txtMultiLineText.text) + f.Free() - if ok == 1: - assert f.txtMultiLineText.text == f.txtMultiLineText.value - print(f.txtMultiLineText.text) - - f.Free() # -------------------------------------------------------------------------- -class MyForm3(Form): +class multiline_text_and_dropdowns_t(ida_kernwin.Form): """Simple Form to test multilinetext and combo box controls""" def __init__(self): self.__n = 0 - Form.__init__(self, + F = ida_kernwin.Form + F.__init__(self, r"""BUTTON YES* Yeah BUTTON NO Nope BUTTON CANCEL NONE @@ -286,18 +246,18 @@ Dropdown list test """, { - 'FormChangeCb': Form.FormChangeCb(self.OnFormChange), - 'cbReadonly': Form.DropdownListControl( + 'FormChangeCb': F.FormChangeCb(self.OnFormChange), + 'cbReadonly': F.DropdownListControl( items=["red", "green", "blue"], readonly=True, selval=1), - 'cbEditable': Form.DropdownListControl( + 'cbEditable': F.DropdownListControl( items=["1MB", "2MB", "3MB", "4MB"], readonly=False, selval="4MB"), - 'iButtonAddelement': Form.ButtonInput(self.OnButtonNop), - 'iButtonSetIndex': Form.ButtonInput(self.OnButtonNop), - 'iButtonSetString': Form.ButtonInput(self.OnButtonNop), + 'iButtonAddelement': F.ButtonInput(self.OnButtonNop), + 'iButtonSetIndex': F.ButtonInput(self.OnButtonNop), + 'iButtonSetString': F.ButtonInput(self.OnButtonNop), }) @@ -307,11 +267,11 @@ Dropdown list test def OnFormChange(self, fid): if fid == self.iButtonSetString.id: - s = ask_str("none", 0, "Enter value") + s = ida_kernwin.ask_str("none", 0, "Enter value") if s: self.SetControlValue(self.cbEditable, s) elif fid == self.iButtonSetIndex.id: - s = ask_str("1", 0, "Enter index value:") + s = ida_kernwin.ask_str("1", 0, "Enter index value:") if s: try: i = int(s) @@ -328,39 +288,34 @@ Dropdown list test s = self.GetControlValue(self.cbEditable) print("user entered: %s" % s) sel_idx = self.GetControlValue(self.cbReadonly) - return 1 -# -------------------------------------------------------------------------- -def test_dropdown(execute=True): - """Test the combobox controls, in a modal dialog""" - f = MyForm3() - f, args = f.Compile() - if execute: - ok = f.Execute() - else: - print(args[0]) - print(args[1:]) - ok = 0 + @staticmethod + def test(execute=True): + f = multiline_text_and_dropdowns_t() + f, args = f.Compile() + if execute: + ok = f.Execute() + else: + print(args[0]) + print(args[1:]) + ok = 0 + if ok == 1: + print("Editable: %s" % f.cbEditable.value) + print("Readonly: %s" % f.cbReadonly.value) + f.Free() - if ok == 1: - print("Editable: %s" % f.cbEditable.value) - print("Readonly: %s" % f.cbReadonly.value) + NON_MODAL_INSTANCE = None - f.Free() + @staticmethod + def test_non_modal(): + if multiline_text_and_dropdowns_t.NON_MODAL_INSTANCE is None: + f = multiline_text_and_dropdowns_t() + f.modal = False + f.openform_flags = ida_kernwin.PluginForm.FORM_TAB + f, _ = f.Compile() + multiline_text_and_dropdowns_t.NON_MODAL_INSTANCE = f + multiline_text_and_dropdowns_t.NON_MODAL_INSTANCE.Open() # -------------------------------------------------------------------------- -tdn_form = None -def test_dropdown_nomodal(): - """Test the combobox controls, in a non-modal form""" - global tdn_form - if tdn_form is None: - tdn_form = MyForm3() - tdn_form.modal = False - tdn_form.openform_flags = idaapi.PluginForm.FORM_TAB - tdn_form, _ = tdn_form.Compile() - tdn_form.Open() - - -# -------------------------------------------------------------------------- -ida_main() +busy_form_t.test() diff --git a/idapyswitch.cpp b/idapyswitch.cpp index 6b3a0b5..e428390 100644 --- a/idapyswitch.cpp +++ b/idapyswitch.cpp @@ -170,7 +170,12 @@ DECLARE_TYPE_AS_MOVABLE(pylib_version_t); struct pylib_entry_t { pylib_version_t version; +#ifdef __MAC__ pylib_version_t compatibility_version; // only for OSX +#endif +#ifdef __NT__ + qstring display_name; +#endif qstrvec_t paths; bool preferred; @@ -576,7 +581,15 @@ static const char usage_epilog[] = "\n" " 3) The 'manual' way\n" " -------------------\n" +#ifdef __NT__ + " > $ idapyswitch --force-path C:\\Python37\\python3.dll\n" +#else +# ifdef __LINUX__ " > $ idapyswitch --force-path /path/to/libpython3.7dm.so.1.2\n" +# else + " > $ idapyswitch --force-path /path/to/Python.framework/Versions/3.7/Python\n" +# endif +#endif " will pick the path that the user provided.\n" "\n" "Once a version is picked, this tool will do the following:\n" diff --git a/idapyswitch_win.cpp b/idapyswitch_win.cpp index 2c094ac..0c2f9ac 100644 --- a/idapyswitch_win.cpp +++ b/idapyswitch_win.cpp @@ -10,6 +10,7 @@ #define PYTHON_INSTALL_PATH_SUBKEY L"InstallPath" #define PYTHON_DISPLAY_NAME_SUBKEY L"DisplayName" #define PYTHON_SYSVER_SUBKEY L"SysVersion" +#define PYTHON_SYSARCH_SUBKEY L"SysArchitecture" #define PYTHON_INSTALL_PATH_DEFAULT_VALUE L"" //------------------------------------------------------------------------- @@ -160,6 +161,65 @@ static bool probe_python_install_dir_from_dll_path( return true; } +static bool has_appx_path(qstrvec_t paths) +{ + static qstring appx_path; + if ( appx_path.empty() ) + { + HKEY hkey; + if ( RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Appx", 0, KEY_READ, &hkey) == ERROR_SUCCESS ) + { + if ( !read_string(&appx_path, hkey, L"PackageRoot") ) + appx_path = ""; + RegCloseKey(hkey); + } + } + for ( auto path : paths ) + if ( path.find(appx_path) != qstring::npos ) + return true; + + return false; +} +//------------------------------------------------------------------------- +// ignore known bad Pythons: +// 3.8.0 release (https://bugs.python.org/issue37633) +// Anaconda 2019.10 (https://github.com/ContinuumIO/anaconda-issues/issues/11374) +// AppStore Python on Windows 10 (dll can't be loaded from outside of Appx package) +static bool bad_entry(const pylib_entry_t &e) +{ + if ( e.version.major == 3 + && e.version.minor == 8 + && e.version.revision == 0 ) + { + out("Ignoring unusable Python 3.8.0\n"); + return true; + } + if ( e.display_name == "Anaconda 2019.10" ) + { + out("Ignoring unusable Anaconda 2019.10\n"); + return true; + } + if ( has_appx_path(e.paths) ) + { + out("Ignoring unusable AppStore Python\n"); + return true; + } + return false; +} + +//------------------------------------------------------------------------- +static void remove_bad_entries(pylib_entries_t *result) +{ + auto p = result->entries.begin(); + while ( p != result->entries.end() ) + { + if ( bad_entry(*p) ) + p = result->entries.erase(p); + else + ++p; + } +} + //------------------------------------------------------------------------- // given a key to a path like HKLM\SOFTWARE\Python\PythonCore, // - enumerate subkeys and their check InstallPath subkey, using the default value as the directory to the installation @@ -195,6 +255,9 @@ static void enum_python_key(pylib_entries_t *result, const HKEY hkey, qstring *_ pylib_version_t version; bool ok = read_string(&sysver, ihkey, PYTHON_SYSVER_SUBKEY); ok = ok && parse_python_version_str(&version, sysver.c_str()) && version.major >= 3; + qstring arch; + if ( read_string(&arch, ihkey, PYTHON_SYSARCH_SUBKEY) && arch != "64bit" ) + ok = false; if ( ok ) { if ( read_string(&displayname, ihkey, PYTHON_DISPLAY_NAME_SUBKEY) ) @@ -220,6 +283,7 @@ static void enum_python_key(pylib_entries_t *result, const HKEY hkey, qstring *_ out("Found: \"%s\" (version: %s)\n", install_path.c_str(), version.str(&verbuf)); pylib_entry_t &e = result->get_or_create_entry_for_version(version); e.paths.insert(e.paths.end(), paths.begin(), paths.end()); + e.display_name = displayname; } else { @@ -242,7 +306,7 @@ static void enum_python_key(pylib_entries_t *result, const HKEY hkey, qstring *_ } else { - out_verb("Not a Python 3.x or no version info, skipping\n"); + out_verb("Not a 64-bit Python 3.x or no version info, skipping\n"); } RegCloseKey(ihkey); @@ -299,6 +363,8 @@ void pyver_tool_t::do_find_python_libs(pylib_entries_t *result) const } } + remove_bad_entries(result); + // // See if we already have one registered for IDA // diff --git a/idapython.cpp b/idapython.cpp index 458ce67..90e95b5 100644 --- a/idapython.cpp +++ b/idapython.cpp @@ -1966,7 +1966,7 @@ bool IDAPython_Init(void) { *lastslash = 0; #ifdef PY3 - qvector buf; + static qvector buf; Py_SetPythonHome(utf8_wchar_t(&buf, pyhomepath)); #else Py_SetPythonHome(pyhomepath); diff --git a/makefile b/makefile index ed2f58f..12fa010 100644 --- a/makefile +++ b/makefile @@ -1,3 +1,10 @@ + +ifeq ($(PYTHON_VERSION_MAJOR),3) + OBJDIR=obj/$(SYSDIR)/3 +else + OBJDIR=obj/$(SYSDIR)/2 +endif + include ../../allmake.mak #---------------------------------------------------------------------- @@ -793,7 +800,7 @@ ifeq ($(OUT_OF_TREE_BUILD),) --exclude=docs/hr-html/ \ --exclude=**/*~ \ . $(PUBTREE_DIR) - (cd $(F) && zip -r ../../$(PUBTREE_DIR)/out_of_tree/parsed_notifications.zip parsed_notifications) + (cd $(F) && zip -r ../../../$(PUBTREE_DIR)/out_of_tree/parsed_notifications.zip parsed_notifications) endif IDAPYSWITCH_OBJS += $(F)idapyswitch$(O) diff --git a/out_of_tree/parsed_notifications.zip b/out_of_tree/parsed_notifications.zip index b527e67..d68c926 100644 Binary files a/out_of_tree/parsed_notifications.zip and b/out_of_tree/parsed_notifications.zip differ diff --git a/pywraps/py_hexrays.py b/pywraps/py_hexrays.py index eff975b..250806b 100644 --- a/pywraps/py_hexrays.py +++ b/pywraps/py_hexrays.py @@ -155,72 +155,6 @@ def cinsn_details(self): return getattr(self, 'c' + opname) cinsn_t.details = property(cinsn_details) -def cblock_iter(self): - - iter = self.begin() - for i in range(self.size()): - yield iter.cur - next(iter) - - return -cblock_t.__iter__ = cblock_iter -cblock_t.__len__ = cblock_t.size - -# cblock.find(cinsn_t) -> returns the iterator positioned at the given item -def cblock_find(self, item): - - iter = self.begin() - for i in range(self.size()): - if iter.cur == item: - return iter - next(iter) - - return -cblock_t.find = cblock_find - -# cblock.index(cinsn_t) -> returns the index of the given item -def cblock_index(self, item): - - iter = self.begin() - for i in range(self.size()): - if iter.cur == item: - return i - next(iter) - - return -cblock_t.index = cblock_index - -# cblock.at(int) -> returns the item at the given index index -def cblock_at(self, index): - - iter = self.begin() - for i in range(self.size()): - if i == index: - return iter.cur - next(iter) - - return -cblock_t.at = cblock_at - -# cblock.remove(cinsn_t) -def cblock_remove(self, item): - - iter = self.find(item) - self.erase(iter) - - return -cblock_t.remove = cblock_remove - -# cblock.insert(index, cinsn_t) -def cblock_insert(self, index, item): - - pos = self.at(index) - iter = self.find(pos) - self.insert(iter, item) - - return -cblock_t.insert = cblock_insert - cfuncptr_t.__str__ = lambda self: str(self.__deref__()) cfuncptr_t.__eq__ = lambda self, other: self.__ptrval__() == other.__ptrval__() diff --git a/pywraps/py_kernwin.py b/pywraps/py_kernwin.py index 7149757..90d6f1a 100644 --- a/pywraps/py_kernwin.py +++ b/pywraps/py_kernwin.py @@ -180,12 +180,12 @@ __wrap_uihooks_callback("populating_widget_popup", lambda cb, *args: cb(*args)) __wrap_uihooks_callback("finish_populating_widget_popup", lambda cb, *args: cb(*args)) __wrap_uihooks_callback("current_widget_changed", lambda cb, *args: cb(*args)) -AskUsingForm=_call_ask_form +AskUsingForm=ask_form HIST_ADDR=0 HIST_NUM=0 KERNEL_VERSION_MAGIC1=0 KERNEL_VERSION_MAGIC2=0 -OpenForm=_call_open_form +OpenForm=open_form _askaddr=_ida_kernwin._ask_addr _asklong=_ida_kernwin._ask_long _askseg=_ida_kernwin._ask_seg diff --git a/pywraps/py_kernwin_askform.py b/pywraps/py_kernwin_askform.py index 0e5c4ea..9277cae 100644 --- a/pywraps/py_kernwin_askform.py +++ b/pywraps/py_kernwin_askform.py @@ -224,6 +224,8 @@ class Form(object): def __init__(self, size=None, value=None): if size is None: raise SyntaxError("The string size must be passed") + if isinstance(size, str): + value, size = size, None self.size = size self.arg = Form.create_string_buffer(value, size) @@ -1216,7 +1218,7 @@ class Form(object): if not self.modal: raise SyntaxError("Form is not modal. Open() should be instead") - return _call_ask_form(*self.__args) + return ask_form(*self.__args) def Open(self): @@ -1227,7 +1229,7 @@ class Form(object): if self.modal: raise SyntaxError("Form is modal. Execute() should be instead") - _call_open_form(*self.__args) + open_form(*self.__args) def EnableField(self, ctrl, enable): @@ -1380,15 +1382,23 @@ except: def __open_form_callable(*args): warning("open_form() needs ctypes library in order to work") - -def _call_ask_form(*args): +def __call_form_callable(call, *args): + assert(len(args)) old = _ida_idaapi.set_script_timeout(0) - r = __ask_form_callable(*args) - _ida_idaapi.set_script_timeout(old) + try: + if sys.version_info.major >= 3 and isinstance(args[0], str): + largs = list(args) + largs[0] = largs[0].encode("UTF-8") + args = tuple(largs) + r = call(*args) + finally: + _ida_idaapi.set_script_timeout(old) return r -def _call_open_form(*args): - old = _ida_idaapi.set_script_timeout(0) - r = __open_form_callable(*args) - _ida_idaapi.set_script_timeout(old) +def ask_form(*args): + return __call_form_callable(__ask_form_callable, *args) + +def open_form(*args): + return __call_form_callable(__open_form_callable, *args) + # diff --git a/pywraps/py_kernwin_choose.hpp b/pywraps/py_kernwin_choose.hpp index 30290df..ab3f39b 100644 --- a/pywraps/py_kernwin_choose.hpp +++ b/pywraps/py_kernwin_choose.hpp @@ -328,14 +328,34 @@ void py_chooser_mixin_t::mixin_get_row( return; if ( list.result != NULL ) { - // Go over the List returned by Python and convert to C strings - for ( int i = chobj->columns - 1; i >= 0; --i ) + if ( PySequence_Check(list.result.o) ) { - borref_t item(PyList_GetItem(list.result.o, Py_ssize_t(i))); - if ( item != NULL ) - IDAPyStr_AsUTF8(&cols->at(i), item.o); + // Go over the List returned by Python and convert to C strings + for ( int i = chobj->columns - 1; i >= 0; --i ) + { + newref_t item(PySequence_GetItem(list.result.o, Py_ssize_t(i))); + if ( item != NULL ) + { + if ( !IDAPyStr_Check(item.o) ) + { + PyErr_Format( + PyExc_TypeError, + "Expected 'str' data for row %" FMT_Z ", column %d", n, i); + break; + } + IDAPyStr_AsUTF8(&cols->at(i), item.o); + } + } + } + else + { + PyErr_Format( + PyExc_TypeError, + "Expected 'list' for row %" FMT_Z, n); } } + if ( PyErr_Occurred() != NULL ) + return; *icon_ = chobj->icon; if ( has_feature(CFEAT_GETICON) ) diff --git a/release_api_contents2.txt b/release_api_contents2.txt index 83cdb30..575a9b7 100644 --- a/release_api_contents2.txt +++ b/release_api_contents2.txt @@ -7842,7 +7842,10 @@ 'qflow_chart_t_title_set', 'qlgetz', 'qlist_cinsn_t___eq__', + 'qlist_cinsn_t___getitem__', + 'qlist_cinsn_t___len__', 'qlist_cinsn_t___ne__', + 'qlist_cinsn_t___setitem__', 'qlist_cinsn_t_back', 'qlist_cinsn_t_back__SWIG_0', 'qlist_cinsn_t_back__SWIG_1', @@ -7861,6 +7864,7 @@ 'qlist_cinsn_t_insert__SWIG_0', 'qlist_cinsn_t_insert__SWIG_1', 'qlist_cinsn_t_insert__SWIG_3', + 'qlist_cinsn_t_insert__SWIG_4', 'qlist_cinsn_t_iterator___eq__', 'qlist_cinsn_t_iterator___ne__', 'qlist_cinsn_t_iterator___next__', @@ -7874,6 +7878,7 @@ 'qlist_cinsn_t_rbegin', 'qlist_cinsn_t_rbegin__SWIG_0', 'qlist_cinsn_t_rbegin__SWIG_1', + 'qlist_cinsn_t_remove', 'qlist_cinsn_t_rend', 'qlist_cinsn_t_rend__SWIG_0', 'qlist_cinsn_t_rend__SWIG_1', diff --git a/release_api_contents3.txt b/release_api_contents3.txt index e2f1d80..ff57690 100644 --- a/release_api_contents3.txt +++ b/release_api_contents3.txt @@ -7846,7 +7846,10 @@ 'qflow_chart_t_title_set', 'qlgetz', 'qlist_cinsn_t___eq__', + 'qlist_cinsn_t___getitem__', + 'qlist_cinsn_t___len__', 'qlist_cinsn_t___ne__', + 'qlist_cinsn_t___setitem__', 'qlist_cinsn_t_back', 'qlist_cinsn_t_back__SWIG_0', 'qlist_cinsn_t_back__SWIG_1', @@ -7865,6 +7868,7 @@ 'qlist_cinsn_t_insert__SWIG_0', 'qlist_cinsn_t_insert__SWIG_1', 'qlist_cinsn_t_insert__SWIG_3', + 'qlist_cinsn_t_insert__SWIG_4', 'qlist_cinsn_t_iterator___eq__', 'qlist_cinsn_t_iterator___ne__', 'qlist_cinsn_t_iterator___next__', @@ -7878,6 +7882,7 @@ 'qlist_cinsn_t_rbegin', 'qlist_cinsn_t_rbegin__SWIG_0', 'qlist_cinsn_t_rbegin__SWIG_1', + 'qlist_cinsn_t_remove', 'qlist_cinsn_t_rend', 'qlist_cinsn_t_rend__SWIG_0', 'qlist_cinsn_t_rend__SWIG_1', diff --git a/release_pydoc_injections2.txt b/release_pydoc_injections2.txt index db4f426..a649484 100644 --- a/release_pydoc_injections2.txt +++ b/release_pydoc_injections2.txt @@ -18301,35 +18301,6 @@ class casm_t(ida_pro.eavec_t)↗ | __weakref__ | list of weak references to the object (if defined) -Help on function cblock_at in module ida_hexrays: - -cblock_at(self, index) - # cblock.at(int) -> returns the item at the given index index - -Help on function cblock_find in module ida_hexrays: - -cblock_find(self, item) - # cblock.find(cinsn_t) -> returns the iterator positioned at the given item - -Help on function cblock_index in module ida_hexrays: - -cblock_index(self, item) - # cblock.index(cinsn_t) -> returns the index of the given item - -Help on function cblock_insert in module ida_hexrays: - -cblock_insert(self, index, item) - # cblock.insert(index, cinsn_t) - -Help on function cblock_iter in module ida_hexrays: - -cblock_iter(self) - -Help on function cblock_remove in module ida_hexrays: - -cblock_remove(self, item) - # cblock.remove(cinsn_t) - Help on class cblock_t in module ida_hexrays: class cblock_t(qlist_cinsn_t) @@ -18354,14 +18325,9 @@ class cblock_t(qlist_cinsn_t) | __init__(self, *args) | __init__(self) -> cblock_t | - | __iter__ = cblock_iter(self) - | | __le__(self, *args) | __le__(self, r) -> bool | - | __len__ = size(self, *args) - | size(self) -> size_t - | | __lt__(self, *args) | __lt__(self, r) -> bool | @@ -18373,24 +18339,9 @@ class cblock_t(qlist_cinsn_t) | _deregister(self, *args) | _deregister(self) | - | at = cblock_at(self, index) - | # cblock.at(int) -> returns the item at the given index index - | | compare(self, *args) | compare(self, r) -> int | - | find = cblock_find(self, item) - | # cblock.find(cinsn_t) -> returns the iterator positioned at the given item - | - | index = cblock_index(self, item) - | # cblock.index(cinsn_t) -> returns the index of the given item - | - | insert = cblock_insert(self, index, item) - | # cblock.insert(index, cinsn_t) - | - | remove = cblock_remove(self, item) - | # cblock.remove(cinsn_t) - | | ---------------------------------------------------------------------- | Data descriptors defined here: | @@ -18406,9 +18357,22 @@ class cblock_t(qlist_cinsn_t) | ---------------------------------------------------------------------- | Methods inherited from qlist_cinsn_t: | - | back(self, *args) - | back(self) -> cinsn_t - | back(self) -> cinsn_t + | __getitem__(self, *args) + | __getitem__(self, i) -> cinsn_t + | + | __iter__ = _bounded_getitem_iterator(self) + | Helper function, to be set as __iter__ method for qvector-, or array-based classes. + | + | __len__(self, *args) + | __len__(self) -> size_t + | + | __setitem__(self, *args) + | __setitem__(self, i, v) + | + | at(self, index) + | + | back = _qvector_back(self) + | # ----------------------------------------------------------------------- | | begin(self, *args) | begin(self) -> qlist_cinsn_t_iterator @@ -18427,9 +18391,18 @@ class cblock_t(qlist_cinsn_t) | erase(self, p1, p2) | erase(self, p) | - | front(self, *args) - | front(self) -> cinsn_t - | front(self) -> cinsn_t + | find(self, item) + | + | front = _qvector_front(self) + | # ----------------------------------------------------------------------- + | + | index(self, item) + | + | insert(self, *args) + | insert(self, p, x) -> qlist< cinsn_t >::iterator + | insert(self, p) -> qlist< cinsn_t >::iterator + | insert(self, i, v) + | insert(self, p, x) -> qlist_cinsn_t_iterator | | pop_back(self, *args) | pop_back(self) @@ -18448,6 +18421,9 @@ class cblock_t(qlist_cinsn_t) | rbegin(self) -> qlist< cinsn_t >::reverse_iterator | rbegin(self) -> qlist< cinsn_t >::const_reverse_iterator | + | remove(self, *args) + | remove(self, v) -> bool + | | rend(self, *args) | rend(self) -> qlist< cinsn_t >::reverse_iterator | rend(self) -> qlist< cinsn_t >::const_reverse_iterator @@ -29296,18 +29272,31 @@ class qlist_cinsn_t(__builtin__.object) | __eq__(self, *args) | __eq__(self, x) -> bool | + | __getitem__(self, *args) + | __getitem__(self, i) -> cinsn_t + | | __init__(self, *args) | __init__(self) -> qlist_cinsn_t | __init__(self, x) -> qlist_cinsn_t | + | __iter__ = _bounded_getitem_iterator(self) + | Helper function, to be set as __iter__ method for qvector-, or array-based classes. + | + | __len__(self, *args) + | __len__(self) -> size_t + | | __ne__(self, *args) | __ne__(self, x) -> bool | | __repr__ = _swig_repr(self) | - | back(self, *args) - | back(self) -> cinsn_t - | back(self) -> cinsn_t + | __setitem__(self, *args) + | __setitem__(self, i, v) + | + | at(self, index) + | + | back = _qvector_back(self) + | # ----------------------------------------------------------------------- | | begin(self, *args) | begin(self) -> qlist_cinsn_t_iterator @@ -29326,13 +29315,17 @@ class qlist_cinsn_t(__builtin__.object) | erase(self, p1, p2) | erase(self, p) | - | front(self, *args) - | front(self) -> cinsn_t - | front(self) -> cinsn_t + | find(self, item) + | + | front = _qvector_front(self) + | # ----------------------------------------------------------------------- + | + | index(self, item) | | insert(self, *args) | insert(self, p, x) -> qlist< cinsn_t >::iterator | insert(self, p) -> qlist< cinsn_t >::iterator + | insert(self, i, v) | insert(self, p, x) -> qlist_cinsn_t_iterator | | pop_back(self, *args) @@ -29352,6 +29345,9 @@ class qlist_cinsn_t(__builtin__.object) | rbegin(self) -> qlist< cinsn_t >::reverse_iterator | rbegin(self) -> qlist< cinsn_t >::const_reverse_iterator | + | remove(self, *args) + | remove(self, v) -> bool + | | rend(self, *args) | rend(self) -> qlist< cinsn_t >::reverse_iterator | rend(self) -> qlist< cinsn_t >::const_reverse_iterator @@ -44896,7 +44892,7 @@ class UI_Hooks(__builtin__.object) | @return: Ignored | | preprocess_action(self, *args) - | preprocess_action(self, name) + | preprocess_action(self, name) -> int | | | IDA ui is about to handle a user action @@ -45071,6 +45067,10 @@ class View_Hooks(__builtin__.object) | __swig_destroy__ = | delete_View_Hooks(self) +Help on function __call_form_callable in module ida_kernwin: + +__call_form_callable(call, *args) + Help on class __qtimer_t in module ida_kernwin: class __qtimer_t(__builtin__.object) @@ -45116,14 +45116,6 @@ Help on function _ask_seg in module ida_kernwin: _ask_seg(*args) _ask_seg(sel, format) -> bool -Help on function _call_ask_form in module ida_kernwin: - -_call_ask_form(*args) - -Help on function _call_open_form in module ida_kernwin: - -_call_open_form(*args) - Help on class action_ctx_base_t in module ida_kernwin: class action_ctx_base_t(__builtin__.object) @@ -45473,6 +45465,10 @@ ask_for_feedback(*args) @param format: the reason why the input file is bad (C++: const char *) +Help on function ask_form in module ida_kernwin: + +ask_form(*args) + Help on function ask_ident in module ida_kernwin: ask_ident(defval, format) @@ -47479,6 +47475,10 @@ open_exports_window(*args) @param ea: index of entry to select by default (C++: ea_t) @return: pointer to resulting window +Help on function open_form in module ida_kernwin: + +open_form(*args) + Help on function open_frame_window in module ida_kernwin: open_frame_window(*args) diff --git a/release_pydoc_injections3.txt b/release_pydoc_injections3.txt index 8b6ade0..adf4b2a 100644 --- a/release_pydoc_injections3.txt +++ b/release_pydoc_injections3.txt @@ -18255,35 +18255,6 @@ class casm_t(ida_pro.eavec_t)↗ | __weakref__ | list of weak references to the object (if defined) -Help on function cblock_at in module ida_hexrays: - -cblock_at(self, index) - # cblock.at(int) -> returns the item at the given index index - -Help on function cblock_find in module ida_hexrays: - -cblock_find(self, item) - # cblock.find(cinsn_t) -> returns the iterator positioned at the given item - -Help on function cblock_index in module ida_hexrays: - -cblock_index(self, item) - # cblock.index(cinsn_t) -> returns the index of the given item - -Help on function cblock_insert in module ida_hexrays: - -cblock_insert(self, index, item) - # cblock.insert(index, cinsn_t) - -Help on function cblock_iter in module ida_hexrays: - -cblock_iter(self) - -Help on function cblock_remove in module ida_hexrays: - -cblock_remove(self, item) - # cblock.remove(cinsn_t) - Help on class cblock_t in module ida_hexrays: class cblock_t(qlist_cinsn_t) @@ -18308,14 +18279,9 @@ class cblock_t(qlist_cinsn_t) | __init__(self, *args) | __init__(self) -> cblock_t | - | __iter__ = cblock_iter(self) - | | __le__(self, *args) -> 'bool' | __le__(self, r) -> bool | - | __len__ = size(self, *args) -> 'size_t' - | size(self) -> size_t - | | __lt__(self, *args) -> 'bool' | __lt__(self, r) -> bool | @@ -18330,24 +18296,9 @@ class cblock_t(qlist_cinsn_t) | _deregister(self, *args) -> 'void' | _deregister(self) | - | at = cblock_at(self, index) - | # cblock.at(int) -> returns the item at the given index index - | | compare(self, *args) -> 'int' | compare(self, r) -> int | - | find = cblock_find(self, item) - | # cblock.find(cinsn_t) -> returns the iterator positioned at the given item - | - | index = cblock_index(self, item) - | # cblock.index(cinsn_t) -> returns the index of the given item - | - | insert = cblock_insert(self, index, item) - | # cblock.insert(index, cinsn_t) - | - | remove = cblock_remove(self, item) - | # cblock.remove(cinsn_t) - | | ---------------------------------------------------------------------- | Data descriptors defined here: | @@ -18362,9 +18313,22 @@ class cblock_t(qlist_cinsn_t) | ---------------------------------------------------------------------- | Methods inherited from qlist_cinsn_t: | - | back(self, *args) -> 'cinsn_t const &' - | back(self) -> cinsn_t - | back(self) -> cinsn_t + | __getitem__(self, *args) -> 'cinsn_t const &' + | __getitem__(self, i) -> cinsn_t + | + | __iter__ = _bounded_getitem_iterator(self) + | Helper function, to be set as __iter__ method for qvector-, or array-based classes. + | + | __len__(self, *args) -> 'size_t' + | __len__(self) -> size_t + | + | __setitem__(self, *args) -> 'void' + | __setitem__(self, i, v) + | + | at(self, index) + | + | back = _qvector_back(self) + | # ----------------------------------------------------------------------- | | begin(self, *args) -> 'qlist_cinsn_t_iterator' | begin(self) -> qlist_cinsn_t_iterator @@ -18383,9 +18347,18 @@ class cblock_t(qlist_cinsn_t) | erase(self, p1, p2) | erase(self, p) | - | front(self, *args) -> 'cinsn_t const &' - | front(self) -> cinsn_t - | front(self) -> cinsn_t + | find(self, item) + | + | front = _qvector_front(self) + | # ----------------------------------------------------------------------- + | + | index(self, item) + | + | insert(self, *args) -> 'qlist_cinsn_t_iterator' + | insert(self, p, x) -> qlist< cinsn_t >::iterator + | insert(self, p) -> qlist< cinsn_t >::iterator + | insert(self, i, v) + | insert(self, p, x) -> qlist_cinsn_t_iterator | | pop_back(self, *args) -> 'void' | pop_back(self) @@ -18404,6 +18377,9 @@ class cblock_t(qlist_cinsn_t) | rbegin(self) -> qlist< cinsn_t >::reverse_iterator | rbegin(self) -> qlist< cinsn_t >::const_reverse_iterator | + | remove(self, *args) -> 'bool' + | remove(self, v) -> bool + | | rend(self, *args) -> 'qlist< cinsn_t >::const_reverse_iterator' | rend(self) -> qlist< cinsn_t >::reverse_iterator | rend(self) -> qlist< cinsn_t >::const_reverse_iterator @@ -29227,21 +29203,34 @@ class qlist_cinsn_t(builtins.object) | __eq__(self, *args) -> 'bool' | __eq__(self, x) -> bool | + | __getitem__(self, *args) -> 'cinsn_t const &' + | __getitem__(self, i) -> cinsn_t + | | __init__(self, *args) | __init__(self) -> qlist_cinsn_t | __init__(self, x) -> qlist_cinsn_t | + | __iter__ = _bounded_getitem_iterator(self) + | Helper function, to be set as __iter__ method for qvector-, or array-based classes. + | + | __len__(self, *args) -> 'size_t' + | __len__(self) -> size_t + | | __ne__(self, *args) -> 'bool' | __ne__(self, x) -> bool | | __repr__ = _swig_repr(self) | + | __setitem__(self, *args) -> 'void' + | __setitem__(self, i, v) + | | __swig_destroy__ = delete_qlist_cinsn_t(...) | delete_qlist_cinsn_t(self) | - | back(self, *args) -> 'cinsn_t const &' - | back(self) -> cinsn_t - | back(self) -> cinsn_t + | at(self, index) + | + | back = _qvector_back(self) + | # ----------------------------------------------------------------------- | | begin(self, *args) -> 'qlist_cinsn_t_iterator' | begin(self) -> qlist_cinsn_t_iterator @@ -29260,13 +29249,17 @@ class qlist_cinsn_t(builtins.object) | erase(self, p1, p2) | erase(self, p) | - | front(self, *args) -> 'cinsn_t const &' - | front(self) -> cinsn_t - | front(self) -> cinsn_t + | find(self, item) + | + | front = _qvector_front(self) + | # ----------------------------------------------------------------------- + | + | index(self, item) | | insert(self, *args) -> 'qlist_cinsn_t_iterator' | insert(self, p, x) -> qlist< cinsn_t >::iterator | insert(self, p) -> qlist< cinsn_t >::iterator + | insert(self, i, v) | insert(self, p, x) -> qlist_cinsn_t_iterator | | pop_back(self, *args) -> 'void' @@ -29286,6 +29279,9 @@ class qlist_cinsn_t(builtins.object) | rbegin(self) -> qlist< cinsn_t >::reverse_iterator | rbegin(self) -> qlist< cinsn_t >::const_reverse_iterator | + | remove(self, *args) -> 'bool' + | remove(self, v) -> bool + | | rend(self, *args) -> 'qlist< cinsn_t >::const_reverse_iterator' | rend(self) -> qlist< cinsn_t >::reverse_iterator | rend(self) -> qlist< cinsn_t >::const_reverse_iterator @@ -45052,8 +45048,8 @@ class UI_Hooks(builtins.object) | | @return: Ignored | - | preprocess_action(self, *args) -> 'void' - | preprocess_action(self, name) + | preprocess_action(self, *args) -> 'int' + | preprocess_action(self, name) -> int | | | IDA ui is about to handle a user action @@ -45219,6 +45215,10 @@ class View_Hooks(builtins.object) | thisown | The membership flag +Help on function __call_form_callable in module ida_kernwin: + +__call_form_callable(call, *args) + Help on class __qtimer_t in module ida_kernwin: class __qtimer_t(builtins.object) @@ -45261,14 +45261,6 @@ Help on function _ask_seg in module ida_kernwin: _ask_seg(*args) -> 'sel_t *' _ask_seg(sel, format) -> bool -Help on function _call_ask_form in module ida_kernwin: - -_call_ask_form(*args) - -Help on function _call_open_form in module ida_kernwin: - -_call_open_form(*args) - Help on class action_ctx_base_t in module ida_kernwin: class action_ctx_base_t(builtins.object) @@ -45610,6 +45602,10 @@ ask_for_feedback(*args) -> 'void' @param format: the reason why the input file is bad (C++: const char *) +Help on function ask_form in module ida_kernwin: + +ask_form(*args) + Help on function ask_ident in module ida_kernwin: ask_ident(defval, format) @@ -47605,6 +47601,10 @@ open_exports_window(*args) -> 'TWidget *' @param ea: index of entry to select by default (C++: ea_t) @return: pointer to resulting window +Help on function open_form in module ida_kernwin: + +open_form(*args) + Help on function open_frame_window in module ida_kernwin: open_frame_window(*args) -> 'TWidget *' @@ -54115,7 +54115,7 @@ retrieve_input_file_crc32(*args) -> 'uint32' Help on function retrieve_input_file_md5 in module ida_nalt: retrieve_input_file_md5(*args) -> 'uchar [ANY]' - retrieve_input_file_md5() -> str + retrieve_input_file_md5() -> bytes Get input file md5. @@ -54123,7 +54123,7 @@ retrieve_input_file_md5(*args) -> 'uchar [ANY]' Help on function retrieve_input_file_sha256 in module ida_nalt: retrieve_input_file_sha256(*args) -> 'uchar [ANY]' - retrieve_input_file_sha256() -> str + retrieve_input_file_sha256() -> bytes Get input file sha256. @@ -77858,7 +77858,7 @@ resume_thread(*args) -> 'int' Help on function retrieve_input_file_md5 in module ida_nalt: retrieve_input_file_md5(*args) -> 'uchar [ANY]' - retrieve_input_file_md5() -> str + retrieve_input_file_md5() -> bytes Get input file md5. diff --git a/tools/bb.py b/tools/bb.py new file mode 100644 index 0000000..b75e51b --- /dev/null +++ b/tools/bb.py @@ -0,0 +1,120 @@ + +import os +import sys +import subprocess + + +ossfx, compiler, sosfx, buildcmd, py2_env, py3_env = { + "win32" : ( + "win", + "vc", + "dll", + "mo.bat -j 12 && mmo.bat -j 12", + { + "PYTHON_VERSION_MAJOR" : "2", + "PYTHON_VERSION_MINOR" : "7", + "PYTHON_ROOT" : "C:/Python27-x64", + }, + { + "PYTHON_VERSION_MAJOR" : "3", + "PYTHON_VERSION_MINOR" : "7", + "PYTHON_ROOT" : "C:/PROGRA~1/Python37", + }, + ), + "cygwin" : ( + "win", + "vc", + "dll", + "mo.bat -j 12 && mmo.bat -j 12", + { + "PYTHON_VERSION_MAJOR" : "2", + "PYTHON_VERSION_MINOR" : "7", + "PYTHON_ROOT" : "C:/Python27-x64", + }, + { + "PYTHON_VERSION_MAJOR" : "3", + "PYTHON_VERSION_MINOR" : "7", + "PYTHON_ROOT" : "C:/PROGRA~1/Python37", + }, + ), + "linux2" : ( + "linux", + "gcc", + "so", + "NDEBUG=1 BIN/idamake.pl -j 12 && NDEBUG=1 __EA64__=1 BIN/idamake.pl -j 12", + { + "PYTHON_VERSION_MAJOR" : "2", + "PYTHON_VERSION_MINOR" : "7", + }, + { + "PYTHON_VERSION_MAJOR" : "3", + "PYTHON_VERSION_MINOR" : "7", + "PYTHONHOME" : "/opt/Python-3.7.4-x64-install", + "PATH" : "/opt/Python-3.7.4-x64-install/bin:!", + "LD_LIBRARY_PATH" : "/opt/Python-3.7.4-x64-install/lib:!" + }, + ), + "darwin" : ( + "mac", + "clang", + "dylib", + "NDEBUG=1 BIN/idamake.pl -j 12 && NDEBUG=1 __EA64__=1 BIN/idamake.pl -j 12", + { + "PYTHON_VERSION_MAJOR" : "2", + "PYTHON_VERSION_MINOR" : "7", + "PYTHON_ROOT" : "/System/Library/Frameworks/Python.framework/Versions/2.7", + }, + { + "PYTHON_VERSION_MAJOR" : "3", + "PYTHON_VERSION_MINOR" : "7", + "PYTHON_ROOT" : "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7", + }, + ), +}[sys.platform] + +# def run(argv): +# if isinstance(argv, str): +# argv = argv.split() +# print("### Running: %s" % " ".join(argv)) +# subprocess.check_call(argv) + +def run(argv): + if not isinstance(argv, str): + argv = " ".join(argv) + print("### Running: %s" % argv) + subprocess.check_call(argv, shell=True) + +def trash_opt_builds(): + run("rm -rf obj/x64_%s_%s_32_opt obj/x64_%s_%s_64_opt" % ( + ossfx, compiler, + ossfx, compiler)) + +def build_both(): + run(buildcmd.replace("BIN", os.path.join("..", "..", "bin"))) + +def rename_both(version): + J = os.path.join + ppath = J("..", "..", "bin", "x64_%s_%s_opt" % (ossfx, compiler), "plugins") + parts = [""] + if version == 3 and "linux" in sys.platform: + parts.append(".debug") + for part in parts: + for easfx in ["", "64"]: + run("mv %s %s" % ( + J(ppath, "idapython%s.%s%s" % (easfx, sosfx, part)), + J(ppath, "idapython%s.%s.%d%s" % (easfx, sosfx, version, part)))) + + +for py_env, major in [ + (py2_env, 2), + (py3_env, 3) +]: + for key, val in py_env.items(): + was = os.getenv(key) + if was: + val = val.replace("!", was) + print("### Setting: %s=%s" % (key, val)) + os.putenv(key, val) + trash_opt_builds() + build_both() + rename_both(major) diff --git a/tools/deploy/header.i.in b/tools/deploy/header.i.in index d80a2d1..5af0dc3 100644 --- a/tools/deploy/header.i.in +++ b/tools/deploy/header.i.in @@ -207,22 +207,20 @@ if _BC695: // resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_unsigned_int, 0 | 0 ); // instead of that: // resultobj = SWIG_From_unsigned_SS_int(static_cast< unsigned int >(*result)); - inline const T& __getitem__(size_t i) const { + inline const T &__getitem__(size_t i) const + { if ( i >= $self->size() ) throw std::out_of_range("out of bounds access"); return $self->at(i); } - inline void __setitem__(size_t i, const T& v) { + inline void __setitem__(size_t i, const T &v) + { if ( i >= $self->size() ) throw std::out_of_range("out of bounds access"); $self->at(i) = v; } - inline const T &at(size_t i) { - return __getitem__(i); - } - %pythoncode { front = ida_idaapi._qvector_front back = ida_idaapi._qvector_back @@ -230,6 +228,82 @@ if _BC695: } } +//--------------------------------------------------------------------- +%extend qlist { + inline size_t __len__() const { return $self->size(); } + + inline const T &__getitem__(size_t i) const + { + if ( i >= $self->size() ) + throw std::out_of_range("out of bounds access"); + qlist::const_iterator it = $self->begin(); + for ( size_t _i = 0; _i < i; ++_i ) + ++it; + return *it; + } + + inline void __setitem__(size_t i, const T &v) + { + if ( i >= $self->size() ) + throw std::out_of_range("out of bounds access"); + qlist::iterator it = $self->begin(); + for ( size_t _i = 0; _i < i; ++_i ) + ++it; + *it = v; + } + + inline void insert(size_t i, const T &v) + { + if ( i > $self->size() ) + throw std::out_of_range("out of bounds access"); + qlist::iterator it = $self->begin(); + for ( size_t _i = 0; _i < i; ++_i ) + ++it; + $self->insert(it, v); + } + + inline bool remove(const T &v) + { + qlist::iterator it = $self->begin(); + for ( ; it != $self->end(); ++it ) + { + if ( *it == v ) + { + $self->erase(it); + return true; + } + } + return false; + } + + %pythoncode { + front = ida_idaapi._qvector_front + back = ida_idaapi._qvector_back + __iter__ = ida_idaapi._bounded_getitem_iterator + + def find(self, item): + it = self.begin() + for i in range(self.size()): + if it.cur == item: + return it + next(it) + + def index(self, item): + it = self.begin() + for i in range(self.size()): + if it.cur == item: + return i + next(it) + + def at(self, index): + it = self.begin() + for i in range(self.size()): + if i == index: + return it.cur + next(it) + } +} + #if IDAPYTHON_MODULE_hexrays %define %ida_hexrays_wrapper_exception_catch() catch ( const vd_failure_t &e ) { __raise_vdf(e); SWIG_fail; } @@ -538,6 +612,19 @@ SWIGINTERN PyObject *_maybe_sized_binary_result( #if defined(IDA_MODULE_NALT) %{ #include +#ifdef PY3 +SWIGINTERN PyObject *_maybe_byte_array_or_none_result( + PyObject *resultobj, + bool result, + const uchar *bytes, + size_t nbytes) +{ + Py_XDECREF(resultobj); + if ( !result ) + Py_RETURN_NONE; + return IDAPyBytes_FromMemAndSize((const char *) bytes, nbytes); +} +#else SWIGINTERN PyObject *_maybe_byte_array_as_hex_or_none_result( PyObject *resultobj, bool result, @@ -549,13 +636,10 @@ SWIGINTERN PyObject *_maybe_byte_array_as_hex_or_none_result( Py_RETURN_NONE; qstring buf; buf.resize(2*nbytes); - get_hex_string(buf.begin(), buf.length(), bytes, nbytes); -#ifdef PY3 - return PyBytes_FromStringAndSize(buf.c_str(), buf.length()); -#else - return PyString_FromStringAndSize(buf.c_str(), buf.length()); -#endif + get_hex_string(buf.begin(), buf.size(), bytes, nbytes); + return IDAPyBytes_FromMemAndSize(buf.c_str(), buf.length()); } +#endif %} #endif @@ -635,6 +719,19 @@ SWIGINTERN PyObject *_maybe_byte_array_as_hex_or_none_result( //------------------------------------------------------------------------- // md5/sha256 hash retrieval (as hex representation) //------------------------------------------------------------------------- +#ifdef PY3 +%define %byte_array_or_none(PARAM_NAME) +%typemap(in, numinputs=0) uchar PARAM_NAME[ANY] (uchar temp[$1_dim0]) +{ // byte_array_or_none typemap(in, numinputs=0) uchar PARAM_NAME[ANY] (uchar temp[$1_dim0]) + $1 = temp; +} +%typemap(argout) uchar PARAM_NAME[ANY] +{ // byte_array_or_none typemap(argout) uchar PARAM_NAME[ANY] + resultobj = _maybe_byte_array_or_none_result(resultobj, result, $1, $1_dim0); +} +%enddef +%byte_array_or_none(hash); +#else %define %byte_array_as_hex_or_none(PARAM_NAME) %typemap(in, numinputs=0) uchar PARAM_NAME[ANY] (uchar temp[$1_dim0]) { // byte_array_as_hex_or_none typemap(in, numinputs=0) uchar PARAM_NAME[ANY] (uchar temp[$1_dim0]) @@ -646,6 +743,7 @@ SWIGINTERN PyObject *_maybe_byte_array_as_hex_or_none_result( } %enddef %byte_array_as_hex_or_none(hash); +#endif // Check that the argument is a callable Python object //--------------------------------------------------------------------- diff --git a/tools/genhooks/recipe_uihooks.py b/tools/genhooks/recipe_uihooks.py index 0e7390f..508f52e 100644 --- a/tools/genhooks/recipe_uihooks.py +++ b/tools/genhooks/recipe_uihooks.py @@ -47,6 +47,12 @@ recipe = { "load_dbg_dbginfo" : {"ignore" : True}, "broadcast" : {"ignore" : True}, + "preprocess_action" : { + "return" : { + "type" : "int", + "retexpr" : "return 0", + } + }, "populating_widget_popup" : { "params" : { "ctx" : { diff --git a/tools/inject_pydoc.py b/tools/inject_pydoc.py index 4161b4a..d03c3c4 100644 --- a/tools/inject_pydoc.py +++ b/tools/inject_pydoc.py @@ -587,6 +587,7 @@ class idaapi_fixer_t(object): ("resultobj = _maybe_cstring_result_on_charptr_using_allocated_buf(", "str"), ("resultobj = _maybe_cstring_result_on_charptr_using_qbuf(", "str"), ("resultobj = _maybe_byte_array_as_hex_or_none_result(", "str"), + ("resultobj = _maybe_byte_array_or_none_result(", "bytes"), ("resultobj = _sized_cstring_result(", "str"), ]: if l.find(pattern) > -1: