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.
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
------------------------------------
- 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: get_debug_names() was broken with IDA64
- Various bugfixes
- Added Scripts folder containing various IDAPython scripts
Changes from version 1.4.2 to 1.4.3
------------------------------------

View File

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

View File

@ -118,8 +118,8 @@ The end!
def OnFormChange(self, fid):
if fid == self.iButton1.id:
print("Button1 fchg;inv=%s" % self.invert)
self.SetFocusedField(self.rNormal.id)
self.EnableField(self.rError.id, self.invert)
self.SetFocusedField(self.rNormal)
self.EnableField(self.rError, self.invert)
self.invert = not self.invert
elif fid == self.iButton2.id:
g1 = self.GetControlValue(self.cGroup1)
@ -134,6 +134,8 @@ The end!
print(">>fid:%d" % fid)
return 1
# --------------------------------------------------------------------------
def stdalone_main():
f = MyForm()
@ -165,7 +167,8 @@ def ida_main():
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)
@ -188,6 +191,7 @@ def ida_main():
print("No selection")
else:
print("Selection: %s" % sel)
# Dispose the form
f.Free()

View File

@ -1139,6 +1139,24 @@ bool idaapi IDAPython_cli_execute_line(const char *line)
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();
PythonEvalOrExec(line);
end_execution();

View File

@ -1644,12 +1644,9 @@ def GetInputMD5():
@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()):
md5str=""
for i in range(16):
md5str += "%02x" % ua[i]
return md5str
return "".join(["%02X" % ua[i] for i in xrange(16)])
else:
return None

View File

@ -2072,6 +2072,21 @@ def struct_unpack(buffer, signed = False, offs = 0):
# Unpack
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):
"""
@ -2175,10 +2190,10 @@ class __IDAPython_Completion_Util(object):
s = self.completion[n]
try:
attr = getattr(self.lastmodule, s)
# is it callable?
# Is it callable?
if callable(attr):
return s + "("
# is it iterable?
return s + ("" if line.startswith("?") else "(")
# Is it iterable?
elif isinstance(attr, basestring) or getattr(attr, '__iter__', False):
return s + "["
except:

View File

@ -65,7 +65,12 @@ def AssembleLine(ea, cs, ip, use32, line):
pass
#</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;
char buf[MAXSTR];
@ -93,7 +98,12 @@ def assemble(ea, cs, ip, use32, line):
"""
#</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;
char buf[MAXSTR];
@ -391,6 +401,7 @@ class IDP_Hooks(object):
"""
pass
def unhook(self):
"""
Removes the IDP hook
@ -398,6 +409,7 @@ class IDP_Hooks(object):
"""
pass
def custom_ana(self):
"""
Analyzes and decodes an instruction at idaapi.cmd.ea
@ -410,6 +422,7 @@ class IDP_Hooks(object):
"""
pass
def custom_out(self):
"""
Outputs the instruction defined in idaapi.cmd
@ -418,6 +431,7 @@ class IDP_Hooks(object):
"""
pass
def custom_emu(self):
"""
Emulate instruction, create cross-references, plan to analyze
@ -428,6 +442,7 @@ class IDP_Hooks(object):
"""
pass
def custom_outop(self, op):
"""
Notification to generate operand text.
@ -438,6 +453,7 @@ class IDP_Hooks(object):
@return: Boolean (whether the operand has been outputted or not)
"""
pass
def custom_mnem(self):
"""
@ -447,6 +463,8 @@ class IDP_Hooks(object):
- None: No mnemonic. IDA will use the default mnemonic value if present
- String: The desired mnemonic string
"""
pass
def is_sane_insn(self, no_crefs):
"""
@ -463,6 +481,7 @@ class IDP_Hooks(object):
"""
pass
def may_be_func(self, no_crefs):
"""
Can a function start here?
@ -474,18 +493,21 @@ class IDP_Hooks(object):
"""
pass
def closebase(self):
"""
The database will be closed now
"""
pass
def savebase(self):
"""
The database is being saved. Processor module should
"""
pass
def rename(self, ea, new_name):
"""
The kernel is going to rename a byte.
@ -497,6 +519,8 @@ class IDP_Hooks(object):
- If returns value <=0, then the kernel should
not rename it. See also the 'renamed' event
"""
pass
def renamed(self, ea, new_name, local_name):
"""
@ -508,6 +532,8 @@ class IDP_Hooks(object):
@return: Ignored
"""
pass
def undefine(self, ea):
"""
@ -519,6 +545,8 @@ class IDP_Hooks(object):
bit0 - ignored
bit1 - do not delete srareas at the item end
"""
pass
def make_code(self, ea, size):
"""
@ -527,6 +555,8 @@ class IDP_Hooks(object):
@param size: Instruction size
@return: 1-ok, <=0-the kernel should stop
"""
pass
def make_code(self, ea, size):
"""
@ -535,7 +565,9 @@ class IDP_Hooks(object):
@param size: Instruction size
@return: 1-ok, <=0-the kernel should stop
"""
pass
def make_data(self, ea, flags, tid, len):
"""
A data item is being created
@ -545,14 +577,18 @@ class IDP_Hooks(object):
@param len: data item size
@return: 1-ok, <=0-the kernel should stop
"""
pass
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)
@param short_sig_name: signature name
@return: Ignored
"""
pass
def add_func(self, func):
"""
@ -560,6 +596,8 @@ class IDP_Hooks(object):
@param func: the func_t instance
@return: Ignored
"""
pass
def del_func(self, func):
"""
@ -567,6 +605,8 @@ class IDP_Hooks(object):
@param func: the func_t instance
@return: 1-ok,<=0-do not delete
"""
pass
def is_call_insn(self, ea, func_name):
"""
@ -575,6 +615,8 @@ class IDP_Hooks(object):
@param ea: instruction address
@return: 1-unknown, 0-no, 2-yes
"""
pass
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
@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>
*/
@ -700,6 +759,15 @@ public:
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);
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 &)
{
msg("Exception in IDP Hook function:\n");

View File

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