IDAPython 1.5.1

- Introduced the CLI '?' pseudo-command to retrieve doc strings
- Introduced the CLI '!' pseudo-command to shell execute a command
- Added IDP/assemble notification event
- bugfix: High 64 bit addresses were not parsed correctly in IDA64
- bugfix: AskUsingForm() C function was not wrapped by SWIG
- NextHead()/PrevHead() have optional 2nd parameter now
This commit is contained in:
elias.bachaalany 2011-04-21 14:23:46 +00:00
parent 58a002ce5b
commit 8375368d6d
8 changed files with 178 additions and 24 deletions

View File

@ -1,6 +1,15 @@
Please see http://code.google.com/p/idapython/source/list for a detailed list of changes. Please see http://code.google.com/p/idapython/source/list for a detailed list of changes.
Changes from version 1.5.0 to 1.5.1
------------------------------------
- Introduced the CLI '?' pseudo-command to retrieve doc strings
- Introduced the CLI '!' pseudo-command to shell execute a command
- bugfix: High 64 bit addresses were not parsed correctly in IDA64
- Added IDP/assemble notification event
- bugfix: AskUsingForm() C function was not wrapped by SWIG
- NextHead()/PrevHead() have optional 2nd parameter now
Changes from version 1.4.3 to 1.5.0 Changes from version 1.4.3 to 1.5.0
------------------------------------ ------------------------------------
- IDA Pro 6.1 support - IDA Pro 6.1 support
@ -17,6 +26,7 @@ Changes from version 1.4.3 to 1.5.0
- bugfix: processor_t.id constants were incorrect - bugfix: processor_t.id constants were incorrect
- bugfix: get_debug_names() was broken with IDA64 - bugfix: get_debug_names() was broken with IDA64
- Various bugfixes - Various bugfixes
- Added Scripts folder containing various IDAPython scripts
Changes from version 1.4.2 to 1.4.3 Changes from version 1.4.2 to 1.4.3
------------------------------------ ------------------------------------

View File

@ -36,7 +36,7 @@ else:
# IDAPython version # IDAPython version
VERSION_MAJOR = 1 VERSION_MAJOR = 1
VERSION_MINOR = 5 VERSION_MINOR = 5
VERSION_PATCH = 0 VERSION_PATCH = 1
# Determine Python version # Determine Python version
PYTHON_MAJOR_VERSION = int(platform.python_version()[0]) PYTHON_MAJOR_VERSION = int(platform.python_version()[0])

View File

@ -118,8 +118,8 @@ The end!
def OnFormChange(self, fid): def OnFormChange(self, fid):
if fid == self.iButton1.id: if fid == self.iButton1.id:
print("Button1 fchg;inv=%s" % self.invert) print("Button1 fchg;inv=%s" % self.invert)
self.SetFocusedField(self.rNormal.id) self.SetFocusedField(self.rNormal)
self.EnableField(self.rError.id, self.invert) self.EnableField(self.rError, self.invert)
self.invert = not self.invert self.invert = not self.invert
elif fid == self.iButton2.id: elif fid == self.iButton2.id:
g1 = self.GetControlValue(self.cGroup1) g1 = self.GetControlValue(self.cGroup1)
@ -134,6 +134,8 @@ The end!
print(">>fid:%d" % fid) print(">>fid:%d" % fid)
return 1 return 1
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
def stdalone_main(): def stdalone_main():
f = MyForm() f = MyForm()
@ -165,7 +167,8 @@ def ida_main():
f.rWarnings.checked = True f.rWarnings.checked = True
f.rGreen.selected = True f.rGreen.selected = True
f.iStr1.value = "Hello" f.iStr1.value = "Hello"
f.iFileSave.value = "*.*"
f.iFileOpen.value = "*.*"
# Execute the form # Execute the form
ok = f.Execute() ok = f.Execute()
print("r=%d" % ok) print("r=%d" % ok)
@ -188,6 +191,7 @@ def ida_main():
print("No selection") print("No selection")
else: else:
print("Selection: %s" % sel) print("Selection: %s" % sel)
# Dispose the form # Dispose the form
f.Free() f.Free()

View File

@ -1139,6 +1139,24 @@ bool idaapi IDAPython_cli_execute_line(const char *line)
return false; return false;
} }
//
// Pseudo commands
//
qstring s;
do
{
// Help command?
if ( line[0] == '?' )
s.sprnt("help(%s)", line+1);
// Shell command?
else if ( line[0] == '!' )
s.sprnt("idaapi.IDAPython_ExecSystem(r'%s')", line+1);
else
break;
// Patch the command line pointer
line = s.c_str();
} while (false);
begin_execution(); begin_execution();
PythonEvalOrExec(line); PythonEvalOrExec(line);
end_execution(); end_execution();

View File

@ -1644,12 +1644,9 @@ def GetInputMD5():
@return: MD5 string or None on error @return: MD5 string or None on error
""" """
ua=idaapi.uchar_array(16) ua = idaapi.uchar_array(16)
if idaapi.retrieve_input_file_md5(ua.cast()): if idaapi.retrieve_input_file_md5(ua.cast()):
md5str="" return "".join(["%02X" % ua[i] for i in xrange(16)])
for i in range(16):
md5str += "%02x" % ua[i]
return md5str
else: else:
return None return None

View File

@ -2072,6 +2072,21 @@ def struct_unpack(buffer, signed = False, offs = 0):
# Unpack # Unpack
return struct.unpack_from(__struct_unpack_table[n][signed], buffer, offs)[0] return struct.unpack_from(__struct_unpack_table[n][signed], buffer, offs)[0]
# ------------------------------------------------------------
def IDAPython_ExecSystem(cmd):
"""
Executes a command with popen().
"""
try:
f = os.popen(cmd, "r")
s = ''.join(f.readlines())
f.close()
return s
except Exception, e:
return str(e)
# ------------------------------------------------------------ # ------------------------------------------------------------
def IDAPython_ExecScript(script, g): def IDAPython_ExecScript(script, g):
""" """
@ -2175,10 +2190,10 @@ class __IDAPython_Completion_Util(object):
s = self.completion[n] s = self.completion[n]
try: try:
attr = getattr(self.lastmodule, s) attr = getattr(self.lastmodule, s)
# is it callable? # Is it callable?
if callable(attr): if callable(attr):
return s + "(" return s + ("" if line.startswith("?") else "(")
# is it iterable? # Is it iterable?
elif isinstance(attr, basestring) or getattr(attr, '__iter__', False): elif isinstance(attr, basestring) or getattr(attr, '__iter__', False):
return s + "[" return s + "["
except: except:

View File

@ -65,7 +65,12 @@ def AssembleLine(ea, cs, ip, use32, line):
pass pass
#</pydoc> #</pydoc>
*/ */
static PyObject *AssembleLine(ea_t ea, ea_t cs, ea_t ip, bool use32, const char *line) static PyObject *AssembleLine(
ea_t ea,
ea_t cs,
ea_t ip,
bool use32,
const char *line)
{ {
int inslen; int inslen;
char buf[MAXSTR]; char buf[MAXSTR];
@ -93,7 +98,12 @@ def assemble(ea, cs, ip, use32, line):
""" """
#</pydoc> #</pydoc>
*/ */
bool assemble(ea_t ea, ea_t cs, ea_t ip, bool use32, const char *line) bool assemble(
ea_t ea,
ea_t cs,
ea_t ip,
bool use32,
const char *line)
{ {
int inslen; int inslen;
char buf[MAXSTR]; char buf[MAXSTR];
@ -391,6 +401,7 @@ class IDP_Hooks(object):
""" """
pass pass
def unhook(self): def unhook(self):
""" """
Removes the IDP hook Removes the IDP hook
@ -398,6 +409,7 @@ class IDP_Hooks(object):
""" """
pass pass
def custom_ana(self): def custom_ana(self):
""" """
Analyzes and decodes an instruction at idaapi.cmd.ea Analyzes and decodes an instruction at idaapi.cmd.ea
@ -410,6 +422,7 @@ class IDP_Hooks(object):
""" """
pass pass
def custom_out(self): def custom_out(self):
""" """
Outputs the instruction defined in idaapi.cmd Outputs the instruction defined in idaapi.cmd
@ -418,6 +431,7 @@ class IDP_Hooks(object):
""" """
pass pass
def custom_emu(self): def custom_emu(self):
""" """
Emulate instruction, create cross-references, plan to analyze Emulate instruction, create cross-references, plan to analyze
@ -428,6 +442,7 @@ class IDP_Hooks(object):
""" """
pass pass
def custom_outop(self, op): def custom_outop(self, op):
""" """
Notification to generate operand text. Notification to generate operand text.
@ -438,6 +453,7 @@ class IDP_Hooks(object):
@return: Boolean (whether the operand has been outputted or not) @return: Boolean (whether the operand has been outputted or not)
""" """
pass
def custom_mnem(self): def custom_mnem(self):
""" """
@ -447,6 +463,8 @@ class IDP_Hooks(object):
- None: No mnemonic. IDA will use the default mnemonic value if present - None: No mnemonic. IDA will use the default mnemonic value if present
- String: The desired mnemonic string - String: The desired mnemonic string
""" """
pass
def is_sane_insn(self, no_crefs): def is_sane_insn(self, no_crefs):
""" """
@ -463,6 +481,7 @@ class IDP_Hooks(object):
""" """
pass pass
def may_be_func(self, no_crefs): def may_be_func(self, no_crefs):
""" """
Can a function start here? Can a function start here?
@ -474,18 +493,21 @@ class IDP_Hooks(object):
""" """
pass pass
def closebase(self): def closebase(self):
""" """
The database will be closed now The database will be closed now
""" """
pass pass
def savebase(self): def savebase(self):
""" """
The database is being saved. Processor module should The database is being saved. Processor module should
""" """
pass pass
def rename(self, ea, new_name): def rename(self, ea, new_name):
""" """
The kernel is going to rename a byte. The kernel is going to rename a byte.
@ -497,6 +519,8 @@ class IDP_Hooks(object):
- If returns value <=0, then the kernel should - If returns value <=0, then the kernel should
not rename it. See also the 'renamed' event not rename it. See also the 'renamed' event
""" """
pass
def renamed(self, ea, new_name, local_name): def renamed(self, ea, new_name, local_name):
""" """
@ -508,6 +532,8 @@ class IDP_Hooks(object):
@return: Ignored @return: Ignored
""" """
pass
def undefine(self, ea): def undefine(self, ea):
""" """
@ -519,6 +545,8 @@ class IDP_Hooks(object):
bit0 - ignored bit0 - ignored
bit1 - do not delete srareas at the item end bit1 - do not delete srareas at the item end
""" """
pass
def make_code(self, ea, size): def make_code(self, ea, size):
""" """
@ -527,6 +555,8 @@ class IDP_Hooks(object):
@param size: Instruction size @param size: Instruction size
@return: 1-ok, <=0-the kernel should stop @return: 1-ok, <=0-the kernel should stop
""" """
pass
def make_code(self, ea, size): def make_code(self, ea, size):
""" """
@ -535,7 +565,9 @@ class IDP_Hooks(object):
@param size: Instruction size @param size: Instruction size
@return: 1-ok, <=0-the kernel should stop @return: 1-ok, <=0-the kernel should stop
""" """
pass
def make_data(self, ea, flags, tid, len): def make_data(self, ea, flags, tid, len):
""" """
A data item is being created A data item is being created
@ -545,14 +577,18 @@ class IDP_Hooks(object):
@param len: data item size @param len: data item size
@return: 1-ok, <=0-the kernel should stop @return: 1-ok, <=0-the kernel should stop
""" """
pass
def load_idasgn(self, short_sig_name): def load_idasgn(self, short_sig_name):
""" """
FLIRT signature have been loaded for normal processing FLIRT signature have been loaded for normal processing
(not for recognition of startup sequences) (not for recognition of startup sequences)
@param short_sig_name: signature name @param short_sig_name: signature name
@return: Ignored @return: Ignored
""" """
pass
def add_func(self, func): def add_func(self, func):
""" """
@ -560,6 +596,8 @@ class IDP_Hooks(object):
@param func: the func_t instance @param func: the func_t instance
@return: Ignored @return: Ignored
""" """
pass
def del_func(self, func): def del_func(self, func):
""" """
@ -567,6 +605,8 @@ class IDP_Hooks(object):
@param func: the func_t instance @param func: the func_t instance
@return: 1-ok,<=0-do not delete @return: 1-ok,<=0-do not delete
""" """
pass
def is_call_insn(self, ea, func_name): def is_call_insn(self, ea, func_name):
""" """
@ -575,6 +615,8 @@ class IDP_Hooks(object):
@param ea: instruction address @param ea: instruction address
@return: 1-unknown, 0-no, 2-yes @return: 1-unknown, 0-no, 2-yes
""" """
pass
def is_ret_insn(self, ea, func_name): def is_ret_insn(self, ea, func_name):
""" """
@ -585,6 +627,23 @@ class IDP_Hooks(object):
False: include instructions like "leave" which begins the function epilog False: include instructions like "leave" which begins the function epilog
@return: 1-unknown, 0-no, 2-yes @return: 1-unknown, 0-no, 2-yes
""" """
pass
def assemble(self, ea, cs, ip, use32, line):
"""
Assembles an instruction
@param ea: linear address of instruction
@param cs: cs of instruction
@param ip: ip of instruction
@param use32: is 32bit segment?
@param line: line to assemble
@return: - None to let the underlying processor module assemble the line
- or a string containing the assembled buffer
"""
pass
#</pydoc> #</pydoc>
*/ */
@ -700,6 +759,15 @@ public:
return 0; return 0;
} }
virtual PyObject *assemble(
ea_t ea,
ea_t cs,
ea_t ip,
bool use32,
const char *line)
{
return NULL;
}
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -912,8 +980,36 @@ int idaapi IDP_Callback(void *ud, int notification_code, va_list va)
ret = proxy->is_ret_insn(ea, strict); ret = proxy->is_ret_insn(ea, strict);
break; break;
} }
case processor_t::assemble:
{
ea_t ea = va_arg(va, ea_t);
ea_t cs = va_arg(va, ea_t);
ea_t ip = va_arg(va, ea_t);
bool use32 = va_argi(va, bool);
const char *line = va_arg(va, const char *);
// Extract user buffer (we hardcode the MAXSTR size limit)
uchar *bin = va_arg(va, uchar *);
// Call python
PyObject *py_buffer = proxy->assemble(ea, cs, ip, use32, line);
if ( py_buffer != NULL && PyString_Check(py_buffer) )
{
char *s;
Py_ssize_t len;
if ( PyString_AsStringAndSize(py_buffer, &s, &len) != -1 )
{
if ( len > MAXSTR )
len = MAXSTR;
memcpy(bin, s, len);
ret = len;
}
}
// ret = 0 otherwise
Py_XDECREF(py_buffer);
break;
}
} }
} }
catch (Swig::DirectorException &) catch (Swig::DirectorException &)
{ {
msg("Exception in IDP Hook function:\n"); msg("Exception in IDP Hook function:\n");

View File

@ -700,6 +700,12 @@ static bool formchgcbfa_set_field_value(
} }
#undef DECLARE_FORM_ACTIONS #undef DECLARE_FORM_ACTIONS
static size_t py_get_AskUsingForm()
{
return (size_t)AskUsingForm_c;
}
//</inline(py_kernwin)> //</inline(py_kernwin)>
%} %}
@ -1681,10 +1687,6 @@ PyObject *choose2_find(const char *title)
} }
static size_t py_get_AskUsingForm()
{
return (size_t)AskUsingForm_c;
}
//</code(py_kernwin)> //</code(py_kernwin)>
%} %}
@ -3409,7 +3411,7 @@ class Choose2(object):
# Disable the timeout # Disable the timeout
old = idaapi.set_script_timeout(0) old = idaapi.set_script_timeout(0)
n = _idaapi.choose2_create(self, False) n = _idaapi.choose2_create(self, False)
idaapi.set_script_timeout(old) _idaapi.set_script_timeout(old)
# Delete the modal chooser instance # Delete the modal chooser instance
self.Close() self.Close()
@ -3729,7 +3731,7 @@ class Form(object):
""" """
Free the control Free the control
""" """
# Release parent form reference # Release the parent form reference
self.form = None self.form = None
@ -4201,7 +4203,9 @@ class Form(object):
""" """
self._reset() self._reset()
self.form = form self.form = form
"""Form string"""
self.controls = controls self.controls = controls
"""Dictionary of controls"""
self.__args = None self.__args = None
self.title = None self.title = None
@ -4215,6 +4219,7 @@ class Form(object):
""" """
for ctrl in self.__controls.values(): for ctrl in self.__controls.values():
ctrl.free() ctrl.free()
# Reset the controls # Reset the controls
# (Note that we are not removing the form control attributes, no need) # (Note that we are not removing the form control attributes, no need)
self._reset() self._reset()
@ -4444,12 +4449,21 @@ class Form(object):
return (self, self.__args) return (self, self.__args)
def Compiled(self):
"""
Checks if the form has already been compiled
@return: Boolean
"""
return self.__args is not None
def Execute(self): def Execute(self):
""" """
Displays a compiled form. Displays a compiled form.
@return: 1 - ok ; 0 - cancel @return: 1 - ok ; 0 - cancel
""" """
if self.__args is None: if not self.Compiled():
raise SyntaxError("Form is not compiled") raise SyntaxError("Form is not compiled")
# Call AskUsingForm() # Call AskUsingForm()