mirror of
https://github.com/idapython/src
synced 2026-06-08 14:47:00 +00:00
Merge branch 'master' into fix/idp-hook-example
This commit is contained in:
+4
-1
@@ -1,2 +1,5 @@
|
||||
obj/
|
||||
*.pyc
|
||||
*.pyc
|
||||
idapyswitch*
|
||||
fuzzer/
|
||||
.vscode/
|
||||
|
||||
+9
-5
@@ -13,11 +13,10 @@ REQUIREMENTS
|
||||
- IDA and IDA SDK [> 5.6]
|
||||
http://www.hex-rays.com/idapro/
|
||||
|
||||
- Python [2.5.1, 2.6.1, 2.7]
|
||||
- Python 3.x
|
||||
http://www.python.org/
|
||||
|
||||
- Simplified Wrapper Interface Generator (SWIG)
|
||||
- if you intend to build for Python 2.x: [4.0.1]
|
||||
- if you intend to build for Python 3.x: [4.0.1, with support for -py3-limited-api]
|
||||
|
||||
Hex-Rays cannot guarantee support for IDAPython
|
||||
@@ -31,8 +30,12 @@ REQUIREMENTS
|
||||
On Windows, please refer to the following instructions:
|
||||
`http://www.swig.org/Doc4.0/Windows.html#Windows_cygwin_mingw`
|
||||
On Linux or OSX,
|
||||
(On Ubuntu, you might want to install a couple of packages:
|
||||
`sudo apt install libpcre3-dev yacc bison automake autotools-dev patchelf -y`)
|
||||
|
||||
`sh autogen.sh`, then
|
||||
`configure --prefix=/my/swig-4.0.1-py3-install && make && make install`
|
||||
`./configure --prefix=/my_path_to/swig-4.0.1-py3-install && make && make install`
|
||||
|
||||
|
||||
- Unix utilities (GNU patch on Windows):
|
||||
http://www.research.att.com/sw/tools/uwin/ or
|
||||
@@ -77,13 +80,14 @@ Note: the path you unpack the IDA SDK into cannot contain white spaces,
|
||||
Note: If you want to build for Python3 (let's say you are building for Python 3.8),
|
||||
please set the following environment variables:
|
||||
- export PYTHON_VERSION_MAJOR=3 ('set PYTHON_VERSION_MAJOR=3' on Windows)
|
||||
- export PYTHON_VERSION_MAJOR=8 ('set PYTHON_VERSION_MINOR=8 on Windows)
|
||||
- export PYTHON_VERSION_MINOR=8 ('set PYTHON_VERSION_MINOR=8 on Windows)
|
||||
|
||||
4. Build the plugin
|
||||
|
||||
python build.py --swig-home /my/swig-4.0.1-py3-install --with-hexrays --idc /path/to/ida74_install/idc/idc.idc
|
||||
python build.py --swig-home /my_path_to/swig-4.0.1-py3-install --with-hexrays --ida-install /path/to/ida_install/
|
||||
|
||||
You can also run 'build.py --help' for more information.
|
||||
|
||||
|
||||
5. Install the components as described in README.md
|
||||
|
||||
|
||||
@@ -53,6 +53,8 @@ so we don't have to do it ourselves.
|
||||
When it comes to other types of pull requests (e.g., documentation),
|
||||
it should usually not be necessary to write a test.
|
||||
|
||||
See also [the best practices for tests & examples](examples/README.md)
|
||||
|
||||
|
||||
### How to write tests?
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@ to the C++ SDK which will then be reflected in IDAPython, an *immensely*
|
||||
useful rule-of-thumb is to perform a diff of the autogenerated SWiG wrappers.
|
||||
|
||||
Typically:
|
||||
`cp -R obj/x64_linux_gcc_32/wrappers/ /tmp/wrappers-before`
|
||||
`cp -R obj/x64_linux_gcc_32/3/wrappers/ /tmp/wrappers-before`
|
||||
<recompile...>
|
||||
`git diff /tmp/wrappers-before/ obj/x64_linux_gcc_32/wrappers/`
|
||||
`git diff /tmp/wrappers-before/ obj/x64_linux_gcc_32/3/wrappers/`
|
||||
|
||||
It is always useful to make sure that SWiG did the right thing -- *especially*
|
||||
when modifying typemaps, but not only.
|
||||
@@ -28,17 +28,19 @@ We use the "zzz" placeholder for a module name in this "how-to".
|
||||
|
||||
2. add zzz to the `MODULES_NAMES` var in makefile
|
||||
|
||||
3. add a line to python/idc.py if you want to autoload this module
|
||||
3. add zzz to `SDK_FILES` var in etc/sdk/sdk_files.mak
|
||||
|
||||
4. add a line to python/idc.py if you want to autoload this module
|
||||
```
|
||||
import ida_zzz
|
||||
```
|
||||
|
||||
4. build
|
||||
5. build
|
||||
|
||||
5. update the content of api_contents.txt
|
||||
6. update the content of api_contents.txt
|
||||
(from obj/.../api_contents.txt.new)
|
||||
|
||||
6. rebuild
|
||||
7. rebuild
|
||||
|
||||
7. update the content of pydoc_injections.txt
|
||||
8. update the content of pydoc_injections.txt
|
||||
(from obj/.../pydoc_injections.txt)
|
||||
|
||||
@@ -15,23 +15,22 @@ Latest stable versions of IDAPython are available from
|
||||
## Resources
|
||||
|
||||
The full function cross-reference is readable online at
|
||||
http://www.hex-rays.com/idapro/idapython_docs/
|
||||
https://www.hex-rays.com/products/ida/support/idapython_docs/
|
||||
|
||||
Mailing list for the project is hosted by Google Groups at
|
||||
http://groups.google.com/group/idapython
|
||||
https://groups.google.com/g/idapython
|
||||
|
||||
## Installation from binaries
|
||||
|
||||
1. Install 2.6 or 2.7 from http://www.python.org/
|
||||
1. Install latest Python 3.x version from https://www.python.org/
|
||||
2. Copy the whole "python" directory to `%IDADIR%`
|
||||
3. Copy the contents of the "plugins" directory to the `%IDADIR%\plugins\`
|
||||
4. Copy "python.cfg" to `%IDADIR%\cfg`
|
||||
3. Copy "idapython.cfg" to `%IDADIR%\cfg`
|
||||
|
||||
## Usage
|
||||
|
||||
- Run script: File / Script file (Alt-F7)
|
||||
- Execute Python statement(s) (Ctrl-F3)
|
||||
- Run previously executed script again: View / Recent Scripts (Alt+F9)
|
||||
- Run script: File / Script file (`Alt+F7`)
|
||||
- Execute Python statement(s) (`Shift+F2`)
|
||||
- Run previously executed script again: View / Recent Scripts (`Alt+F9`)
|
||||
|
||||
### Batch mode execution:
|
||||
|
||||
@@ -48,7 +47,7 @@ or
|
||||
-S"yourscript.py arg1 arg2 arg3"
|
||||
```
|
||||
|
||||
(Please see http://www.hexblog.com/?p=128)
|
||||
(Please see https://hex-rays.com/blog/running-scripts-from-the-command-line-with-idascript/)
|
||||
|
||||
If you want fully unattended execution mode, make sure your script
|
||||
exits with a `qexit()` call.
|
||||
@@ -65,7 +64,7 @@ Where N can be:
|
||||
|
||||
### User init file
|
||||
|
||||
You can place your custom settings to a file called 'idapythonrc.py'
|
||||
You can place your custom settings to a file called `idapythonrc.py`
|
||||
that should be placed to
|
||||
```sh
|
||||
${HOME}/.idapro/
|
||||
@@ -76,27 +75,27 @@ or
|
||||
```
|
||||
The user init file is read and executed at the end of the init process.
|
||||
|
||||
Please note that IDAPython can be configured with "python.cfg" file.
|
||||
Please note that IDAPython can be configured with `idapython.cfg` file.
|
||||
|
||||
### Invoking Python from IDC
|
||||
|
||||
The IDAPython plugin exposes a new IDC function `RunPythonStatement(string idc_code)` that allows execution
|
||||
of Python code from IDC
|
||||
The IDAPython plugin exposes a new IDC function `exec_python(string python_code)` that allows execution
|
||||
of Python code from IDC.
|
||||
|
||||
### Invoking IDC from Python
|
||||
|
||||
It is possible to use the `idc.eval()` to evaluate IDC expressions from Python
|
||||
It is possible to use the `idc.eval_idc()` to evaluate IDC expressions from Python.
|
||||
|
||||
### Making Python the default language
|
||||
### Switching the default language between Python and IDC
|
||||
|
||||
By default, IDA will use IDC to evaluate expressions. It is possible to change the default language to use
|
||||
Python instead of IDC.
|
||||
By default, IDA will use IDC to evaluate expressions in dialog boxes and in `eval_expr()`.
|
||||
It is possible to change the default language to Python.
|
||||
|
||||
In order to do that, please use the following IDC code:
|
||||
In order to do that, use the following (IDC/Python) code:
|
||||
```c
|
||||
load_and_run_plugin("python", 3)
|
||||
load_and_run_plugin("idapython", 3)
|
||||
```
|
||||
To disable Python language and revert back to IDC:
|
||||
To go back to IDC, use the following code:
|
||||
```c
|
||||
load_and_run_plugin("python", 4)
|
||||
load_and_run_plugin("idapython", 4)
|
||||
```
|
||||
|
||||
+13
-36
@@ -1,43 +1,20 @@
|
||||
IDAPython requires a Python3.x installation in order to work.
|
||||
|
||||
IDAPython comes in two flavors:
|
||||
Because different users might have different (and possibly multiple)
|
||||
versions of Python3.x installed, IDA comes with a tool called `idapyswitch`
|
||||
that can be run to select the desired Python3.x runtime.
|
||||
|
||||
* IDAPython-for-Python2
|
||||
* IDAPython-for-Python3
|
||||
If you selected IDAPython-for-Python3.x at the installation time,
|
||||
the `idapyswitch` utility should already have been run and selected
|
||||
the most appropriate Python3.x version.
|
||||
|
||||
# Switching between Python 2 and Python 3.
|
||||
|
||||
Depending on your choice at the install time, your "plugins" directory will have
|
||||
one version of plugin installed as idapython.[dll|so|dylib] (and/or idapython64) and
|
||||
the other will be present with the ".disabled" extension. To switch, just rename the
|
||||
current version to .disabled and the disabled one back to the .dll/.so/.dylib
|
||||
(depending on your OS)
|
||||
|
||||
For example, to swith from Python 3 to Python 2 on Windows:
|
||||
|
||||
1. rename idapython.dll to idapython.3.disabled and idapython64.dll to idapython64.3.disabled
|
||||
2. rename idapython2.disabled to idapython.dll and idapython642.disabled to idapython64.dll
|
||||
|
||||
|
||||
# Selecting a Python install to use
|
||||
|
||||
The situation for IDAPython-for-Python2 is simple: it uses Python 2.7,
|
||||
and will expect that [lib]python2.7.[dll|so|dylib] is present in the system
|
||||
library path so that IDA can find it.
|
||||
|
||||
When it comes to IDAPython-for-Python3, it gets more complex: because
|
||||
different users might have different (and possibly multiple) versions
|
||||
of Python3 installed, IDA comes with a tool called `idapyswitch`, that
|
||||
can be run to select the desired Python3 runtime to tailor
|
||||
IDAPython-for-Python3 to.
|
||||
|
||||
If you selected IDAPython-for-Python3 at installation-time,
|
||||
`idapyswitch` utility should already have been run, and selected
|
||||
the most appropriate Python3 version.
|
||||
|
||||
Should you want to switch to another Python3 install after installation,
|
||||
please run `idapyswitch` from IDA's directory. It will scan for Python
|
||||
installs present in the system's standard locations and offer you to choose one.
|
||||
Should you want to switch to another Python3.x install after installation,
|
||||
please run `idapyswitch` from the IDA directory. It will scan for Python
|
||||
installs present in the system's standard locations and offer you to choose one.
|
||||
It also supports optional command-line switches to handle non-standard installs.
|
||||
Run `idapyswitch -h` to see them.
|
||||
|
||||
On Windows, you may need to run it as administrator
|
||||
so it can patch sip.pyd (library required for PyQt bindings).
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ A script that tries to determine the call stack
|
||||
|
||||
Run the application with the debugger, suspend the debugger, select a thread and finally run the script.
|
||||
|
||||
Copyright (c) 1990-2019 Hex-Rays
|
||||
Copyright (c) 1990-2023 Hex-Rays
|
||||
ALL RIGHTS RESERVED.
|
||||
"""
|
||||
import ida_ua
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
A script to demonstrate how to send commands to the debugger and then parse and use the output in IDA
|
||||
|
||||
Copyright (c) 1990-2019 Hex-Rays
|
||||
Copyright (c) 1990-2023 Hex-Rays
|
||||
ALL RIGHTS RESERVED.
|
||||
|
||||
"""
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
This script shows how to send debugger commands and use the result in IDA
|
||||
|
||||
Copyright (c) 1990-2019 Hex-Rays
|
||||
Copyright (c) 1990-2023 Hex-Rays
|
||||
ALL RIGHTS RESERVED.
|
||||
|
||||
"""
|
||||
|
||||
@@ -13,7 +13,7 @@ The general syntax is:
|
||||
* To specify in which context the instructions should be assembled, pass asm_where=ea:
|
||||
find("jmp dword ptr [esp]", asm_where=here())
|
||||
|
||||
Copyright (c) 1990-2019 Hex-Rays
|
||||
Copyright (c) 1990-2023 Hex-Rays
|
||||
ALL RIGHTS RESERVED.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ A script that graphs all the exception handlers in a given process
|
||||
|
||||
It will be easy to see what thread uses what handler and what handlers are commonly used between threads
|
||||
|
||||
Copyright (c) 1990-2019 Hex-Rays
|
||||
Copyright (c) 1990-2023 Hex-Rays
|
||||
ALL RIGHTS RESERVED.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
This script shows how to send debugger commands and use the result in IDA
|
||||
|
||||
Copyright (c) 1990-2019 Hex-Rays
|
||||
Copyright (c) 1990-2023 Hex-Rays
|
||||
ALL RIGHTS RESERVED.
|
||||
|
||||
"""
|
||||
|
||||
@@ -2,7 +2,7 @@ from __future__ import print_function
|
||||
# -----------------------------------------------------------------------
|
||||
# VirusTotal IDA Plugin
|
||||
# By Elias Bachaalany <elias at hex-rays.com>
|
||||
# (c) Hex-Rays 2011-2019
|
||||
# (c) Hex-Rays 2011-2023
|
||||
#
|
||||
# Special thanks:
|
||||
# - VirusTotal team
|
||||
|
||||
+1863
-539
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -21,20 +21,20 @@ had to build/install it yourself, you will have to specify '--swig-home'.
|
||||
|
||||
What follows, are example build commands
|
||||
|
||||
### Windows (assume SWiG is installed in C:\swigwin-2.0.12, and IDA is in C:\Program Files\IDA7)
|
||||
### Windows (assume SWiG is installed in C:\swigwin-4.0.1, and IDA is in C:\Program Files\IDA8)
|
||||
|
||||
python2 build.py \\
|
||||
python3 build.py \\
|
||||
--with-hexrays \\
|
||||
--swig-home C:/swigwin-2.0.12 \\
|
||||
--idc "c:/Program\ Files/IDA_7.0-171130-tests/idc/idc.idc"
|
||||
--swig-home C:/swigwin-4.0.1 \\
|
||||
--ida-install "c:/Program\ Files/IDA_8.0"
|
||||
|
||||
|
||||
### Linux/OSX (assume SWiG is installed in /opt/swiglinux-2.0.12, and IDA is in /opt/my-ida-install)
|
||||
### Linux/OSX (assume SWiG is installed in /opt/swiglinux-4.0.1, and IDA is in /opt/my-ida-install)
|
||||
|
||||
python2 build.py \\
|
||||
python3 build.py \\
|
||||
--with-hexrays \\
|
||||
--swig-home /opt/swiglinux-2.0.12 \\
|
||||
--idc /opt/my-ida-install/idc/idc.idc
|
||||
--swig-home /opt/swiglinux-4.0.1 \\
|
||||
--ida-install /opt/my-ida-install
|
||||
""",
|
||||
formatter_class=argparse.RawTextHelpFormatter)
|
||||
parser.add_argument("--swig-home", type=str, help="Path to the SWIG installation", default=None)
|
||||
@@ -42,10 +42,11 @@ parser.add_argument("--with-hexrays", help="Build Hex-Rays decompiler bindings (
|
||||
parser.add_argument("--debug", help="Build debug version of the plugin", default=False, action="store_true")
|
||||
parser.add_argument("-j", "--parallel", action="store_true", help="Build in parallel", default=False)
|
||||
parser.add_argument("-v", "--verbose", help="Verbose mode", default=False, action="store_true")
|
||||
parser.add_argument("-I", "--idc", required=True, help="IDA's idc.idc file (necessary for generating 6.95 compat API layer)", type=str)
|
||||
parser.add_argument("-I", "--ida-install", required=True, help="IDA's installation directory", type=str)
|
||||
args = parser.parse_args()
|
||||
|
||||
_probe = os.path.join("..", "..", "include", "pro.h")
|
||||
sdk_relpath = os.path.join("..", "..")
|
||||
_probe = os.path.join(sdk_relpath, "include", "pro.h")
|
||||
assert os.path.exists(_probe), "Could not find IDA SDK include path (looked for: \"%s\")" % _probe
|
||||
|
||||
|
||||
@@ -76,7 +77,8 @@ def main():
|
||||
env["NDEBUG"] = "1"
|
||||
if args.verbose:
|
||||
argv.append("-d")
|
||||
env["IDC_BC695_IDC_SOURCE"] = args.idc.replace('\\', '/')
|
||||
env["IDA_INSTALL"] = args.ida_install.replace('\\', '/')
|
||||
env["SDK_BIN_PATH"] = os.path.abspath(os.path.join(sdk_relpath, "bin")).replace('\\', '/')
|
||||
for ea64 in [True, False]:
|
||||
if ea64:
|
||||
env["__EA64__"] = "1"
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
|
||||
IDAPython for IDA 7.00: backward-compatibility with 6.95 APIs
|
||||
=============================================================
|
||||
|
||||
Availability of the backward-compatibility code
|
||||
-----------------------------------------------
|
||||
|
||||
* Backward-compatibility is provided by python.cfg's
|
||||
`AUTOIMPORT_COMPAT_IDA695` directive. This directive is
|
||||
currently turned on by default, but in the future it will:
|
||||
1. be turned off by default
|
||||
1. eventually disappear, and all the corresponding code will be removed
|
||||
|
||||
* Consequently IDAPython script/plugin writers should try and port
|
||||
their code, with the help of the porting guide XXX FIXME URL? XXX.
|
||||
|
||||
* Once you have done the porting, please check that your code works
|
||||
with `AUTOIMPORT_COMPAT_IDA695` set to `NO`.
|
||||
|
||||
* If anything proves too hard or confusing, please let us know about
|
||||
it on <support@hexrays.com>, and we will help you, either by fixing
|
||||
IDAPython if needed, or by improving the documentation.
|
||||
|
||||
|
||||
Coverage of the backward-compatibility code
|
||||
-------------------------------------------
|
||||
|
||||
* We did what was reasonably feasible, to provide an IDAPython API
|
||||
that's as backward-compatible as possible with the IDA 6.95 API
|
||||
|
||||
* However, we considered it unreasonable for some parts of the API
|
||||
to be ported. Most notably:
|
||||
* the "processor module" API: existing processor modules will
|
||||
have to be ported to the new API. Please see the SDK's
|
||||
`module/script/proctemplate.py` (or any other `*.py` file in
|
||||
that directory) for examples how to use the new API.
|
||||
* processor module-related notifications: some of those have either
|
||||
been renamed, or have possibly changed signature
|
||||
|
||||
* Most (all?) of the renamed functions, properties, etc... should be
|
||||
covered, in all modules: `idaapi`, `idc`, ...
|
||||
If something doesn't work/isn't there anymore, it's likely an
|
||||
omission from our side.
|
||||
|
||||
* Please let us know about any missing bits & pieces, that you
|
||||
believe should be there and that we might have forgotten!
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
TARGET_DIR=../../../../www/www.hex-rays.com/public_html/hex-rays/products/ida/7.0/docs
|
||||
TARGET_FILE=$TARGET_DIR/idapython_backward_compat_695.html
|
||||
p4 edit $TARGET_FILE
|
||||
echo \<html\>\<head\> > $TARGET_FILE
|
||||
echo \<link type="text/css" rel="stylesheet" href="../../../../style.css" /\> >> $TARGET_FILE
|
||||
echo \<link type="text/css" rel="stylesheet" href="style.css" /\> >> $TARGET_FILE
|
||||
echo \</head\>\<body\> >> $TARGET_FILE
|
||||
markdown bc695.md >> $TARGET_FILE
|
||||
echo \</body\>\</html\> >> $TARGET_FILE
|
||||
p4 revert -a $TARGET_FILE
|
||||
@@ -0,0 +1,90 @@
|
||||
|
||||
This is an FAQ-style repository of SWiG incantations that are
|
||||
regularly needed.
|
||||
|
||||
# Remove an argument from a prototype (because it doesn't make sense in the context of IDAPython)
|
||||
|
||||
%typemap(in,numinputs=0) int length
|
||||
{
|
||||
$1 = -1; // always -1 in IDAPython
|
||||
}
|
||||
|
||||
# Add a parameter to a C++ notification
|
||||
|
||||
Assume a notification named `struc_renamed`, to which you just
|
||||
added a `bool success` parameter (to carry along information about the
|
||||
operation's success so far):
|
||||
|
||||
struc_renamed, ///< A structure type has been renamed.
|
||||
///< \param sptr (::struc_t *)
|
||||
///< \param success (bool) // <--------- new
|
||||
|
||||
That new parameter will be picked up by the hooks-producing code
|
||||
automatically (great!), which means existing hooks are now broken
|
||||
(bad.)
|
||||
|
||||
We need to add support for calling into "old-style" hooks. That's done
|
||||
through the `patch_codegen.py` mechanism, and in particular the
|
||||
`director_method_call_arity_cap` rule. Something like this should do:
|
||||
|
||||
"SwigDirector_IDB_Hooks::struc_renamed" : [
|
||||
("director_method_call_arity_cap", (
|
||||
False, # add GIL lock
|
||||
"struc_renamed",
|
||||
"(method ,(PyObject *)obj0,(__argcnt < 3 ? nullptr : (PyObject *)obj1), nullptr)",
|
||||
"(swig_get_self(), (PyObject *) swig_method_name ,(PyObject *)obj0,(__argcnt < 3 ? nullptr : (PyObject *)obj1), nullptr)")
|
||||
)),
|
||||
],
|
||||
|
||||
# Handle a virtual method's "output" parameter in a director
|
||||
|
||||
Assume you have a virtual method taking an 'output' argument:
|
||||
|
||||
void merge_node_helper_t::get_column_headers(qstrvec_t *out, ...)
|
||||
|
||||
The neat thing to do here is to let Python implementations do the
|
||||
following:
|
||||
|
||||
def get_column_headers(self, ...):
|
||||
# ...
|
||||
return ["Name", "Address"]
|
||||
|
||||
To achieve that, you want to use the `directorargout` typemap:
|
||||
|
||||
%typemap(directorargout) qstrvec_t * (qstrvec_t tmp)
|
||||
{ // %typemap(directorargout) qstrvec_t *
|
||||
if ( PyW_PyListToStrVec(&tmp, $result) >= 0 )
|
||||
{
|
||||
$1->swap(tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
Swig::DirectorTypeMismatchException::raise(
|
||||
SWIG_ErrorType(SWIG_TypeError),
|
||||
"in output value of type 'qstrvec_t' in method '$symname'");
|
||||
}
|
||||
}
|
||||
|
||||
# "intercept" access to a structure/class field, in order to perform extra work
|
||||
|
||||
For example, `idainfo.lflags` bits should be set using proper setters,
|
||||
because they can have side-effects.
|
||||
|
||||
. tell swig to consider the member as unreachable:
|
||||
|
||||
%ignore idainfo::lflags;
|
||||
|
||||
. extend the type to "manually" provide the field:
|
||||
|
||||
%extend idainfo
|
||||
{
|
||||
// ...
|
||||
uint32 _get_lflags() const { return $self->lflags; }
|
||||
void _set_lflags(uint32 _f)
|
||||
{
|
||||
// do the job here
|
||||
}
|
||||
|
||||
%pythoncode {
|
||||
lflags = property(_get_lflags, _set_lflags)
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
|
||||
# inject_pydoc.py
|
||||
|
||||
This tool is in charge extracting information from the C++ SDK
|
||||
headers, and inject it into IDAPython's documentation.
|
||||
|
||||
## Extracting the C++ SDK information/documentation
|
||||
|
||||
The IDAPython build system will run `doxygen` against the SDK headers,
|
||||
asking it to output all the information it could extract, as `XML`
|
||||
format for later use - by `inject_pydoc.py`, but not only…
|
||||
|
||||
## Applying the documentation
|
||||
|
||||
Then, we run `tools/inject_pydoc.py`, to process that `XML`
|
||||
content and extract documentation about the functions, classes,
|
||||
methods, variables, etc… that are present in the corresponding
|
||||
IDAPython module.
|
||||
|
||||
## Fixing the input parameters
|
||||
|
||||
We cannot blindly apply the SDK documentation, however: some C++
|
||||
function parameters will turn into output values when converted to
|
||||
Python, and thus it makes no sense to have those parameters as part of
|
||||
the IDAPython function documentation. For example, when wrapping
|
||||
|
||||
inline void get_registered_actions(qstrvec_t *out)
|
||||
|
||||
into `ida_kernwin.get_registered_actions`, the `out` parameter will
|
||||
turn into a `list(str)`, so it makes no sense to see the corresponding
|
||||
C++ header's documentation:
|
||||
|
||||
/// \param out the list of actions to be filled
|
||||
|
||||
into the IDAPython documentation.
|
||||
|
||||
Fortunately, we can rely on SWiG's help to do that, because even
|
||||
though SWiG doesn't know how to import C++ header's documentation, it
|
||||
*will* tell us what parameters are present in the wrapped prototype.
|
||||
|
||||
Therefore, we collect the SWiG-generated list of parameters from the
|
||||
prototype, and simply remove the non-relevant bits from the C++
|
||||
header's documentation before injecting that into IDAPython.
|
||||
|
||||
## Fixing the return values
|
||||
|
||||
Because all of that was too easy, IDAPython adds another layer of
|
||||
complexity (craziness?) for fixing the return values.
|
||||
|
||||
When it comes to the input parameters, it's actually _fairly_ easy to
|
||||
drop the irrelevant bits from the C++ SDK header's documentation: we
|
||||
know what parameters SWiG will keep & wrap.
|
||||
|
||||
But for the return values, it's another story entirely: SWiG doesn't
|
||||
know (and cannot always reliably know) what type a return value will
|
||||
have.
|
||||
In particular when it comes to custom code in `pywraps/` that returns
|
||||
a `PyObject *`.
|
||||
|
||||
Therefore, we have put a mechanism into place, that lets us put a
|
||||
"wrapper" around _all_ IDAPython functions/class methods, that will
|
||||
trace/keep track of the types of the values that were passed in, and
|
||||
the types of the values that were spit out by those functions.
|
||||
|
||||
We can then use that wrapper when running tests, collect information
|
||||
from the tests that were run, process that information, and save it
|
||||
into `tools/collected_traces.txt`, which will then be used by
|
||||
`inject_pydoc.py`.
|
||||
|
||||
It's worth pointing out that that information is not, and could not
|
||||
possibly, be generated at build-time: it must be done at another time
|
||||
(e.g., after running tests), which is very different than the
|
||||
mechanism used for fixing the parameters (that "simply" relies on the
|
||||
`doxygen`-parsed `XML`-formatted documentation.)
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
# IDAPython runtime documentation
|
||||
|
||||
We define the "IDAPython runtime documentation" as the documentation
|
||||
that's available through Python's `help()` system, while the user is
|
||||
interacting with `IDAPython` during an IDA session.
|
||||
|
||||
That documentation is SWiG-generated + patched, or custom written.
|
||||
|
||||
## Custom-written documentation
|
||||
|
||||
Some functions have custom-written documentation (check for <pydoc>
|
||||
tags in the `pywraps/` directory), but the general case is that the
|
||||
documentation is automatically generated by SWiG, and then patched.
|
||||
|
||||
## SWiG-generated + patched documentation
|
||||
|
||||
Because SWiG doesn't know about the C++ SDK header's documentation, we
|
||||
need a way to "import" that documentation into IDAPython.
|
||||
|
||||
That's done by `tools/inject_pydoc.py` which deserves
|
||||
[its own documentation](inject_pydoc.md)
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
# IDAPython examples
|
||||
|
||||
This directory contains a variety of examples demonstrating
|
||||
how IDA can be scripted using IDAPython.
|
||||
|
||||
## Adding a new example (for Hex-Rays developers)
|
||||
|
||||
When adding an example, the author (i.e., a Hex-Rays developer)
|
||||
must add a corresponding test, making sure the example is properly
|
||||
tested, and doesn't regress over time (see `idapython-examples`,
|
||||
and `idapython_hr-examples` test suites.) This has the added benefit
|
||||
that this ensures our APIs remain stable.
|
||||
|
||||
Also, any significant addition to IDAPython APIs should come
|
||||
with one or many examples, and those should be also put under test
|
||||
(in other words: it's better if a test relies on a real example,
|
||||
rather than if it consists of a bunch of IDAPython code our
|
||||
users will never see, and cannot be inspired from.)
|
||||
|
||||
## Helping our customers, teaching IDAPython in the process
|
||||
|
||||
In addition, when a customer asks for help on support@ (or the forums)
|
||||
and we end up sending a significant body of IDAPython code as a reply,
|
||||
since that body of code should be tested anyway, it's better to make
|
||||
a real example out of it ... and, of course, put that example under
|
||||
test as well.
|
||||
|
||||
## Maintaining quality
|
||||
|
||||
There should be no such thing as a non-tested example.
|
||||
|
||||
## Updating the examples index
|
||||
|
||||
All examples are automatically integrated in the examples index.
|
||||
In order to show user-friendly & relevant information, a proper
|
||||
header (docstring) needs to be present.
|
||||
@@ -0,0 +1,107 @@
|
||||
"""
|
||||
summary: dump (some) information about the current function.
|
||||
|
||||
description:
|
||||
Dump some of the most interesting bits of information about
|
||||
the function we are currently looking at.
|
||||
"""
|
||||
|
||||
import binascii
|
||||
|
||||
import ida_kernwin
|
||||
import ida_funcs
|
||||
|
||||
|
||||
def dump_flags(fn):
|
||||
"dump some flags of the func_t object"
|
||||
print("Function flags: %08X" % fn.flags)
|
||||
if fn.is_far():
|
||||
print(" Far function")
|
||||
if not fn.does_return():
|
||||
print(" Function does not return")
|
||||
if fn.flags & ida_funcs.FUNC_FRAME:
|
||||
print(" Function uses frame pointer")
|
||||
if fn.flags & ida_funcs.FUNC_THUNK:
|
||||
print(" Thunk function")
|
||||
if fn.flags & ida_funcs.FUNC_LUMINA:
|
||||
print(" Function info is provided by Lumina")
|
||||
if fn.flags & ida_funcs.FUNC_OUTLINE:
|
||||
print(" Outlined code, not a real function")
|
||||
|
||||
|
||||
def dump_regvars(pfn):
|
||||
"dump renamed registers information"
|
||||
assert ida_funcs.is_func_entry(pfn)
|
||||
print("Function has %d renamed registers" % pfn.regvarqty)
|
||||
for rv in pfn.regvars:
|
||||
print("%08X..%08X '%s'->'%s'" % (rv.start_ea, rv.end_ea, rv.canon, rv.user))
|
||||
|
||||
def dump_regargs(pfn):
|
||||
"dump register arguments information"
|
||||
assert ida_funcs.is_func_entry(pfn)
|
||||
print("Function has %d register arguments" % pfn.regargqty)
|
||||
for ra in pfn.regargs:
|
||||
print(" register #=%d, argument name=\"%s\", (serialized) type=\"%s\"" % (
|
||||
ra.reg,
|
||||
ra.name,
|
||||
binascii.hexlify(ra.type)))
|
||||
|
||||
|
||||
def dump_tails(pfn):
|
||||
"dump function tails for entry chunk pfn"
|
||||
assert ida_funcs.is_func_entry(pfn)
|
||||
print("Function has %d tails" % pfn.tailqty)
|
||||
for i in range(pfn.tailqty):
|
||||
ft = pfn.tails[i]
|
||||
print(" tail %i: %08X..%08X" % (i, ft.start_ea, ft.end_ea))
|
||||
|
||||
|
||||
def dump_stkpnts(pfn):
|
||||
"dump function stack points"
|
||||
print("Function has %d stack points" % pfn.pntqty)
|
||||
for i in range(pfn.pntqty):
|
||||
pnt = pfn.points[i]
|
||||
print(" stkpnt %i @%08X: %d" % (i, pnt.ea, pnt.spd))
|
||||
|
||||
|
||||
def dump_frame(fn):
|
||||
"dump function frame info"
|
||||
assert ida_funcs.is_func_entry(fn)
|
||||
print("frame structure id: %08X" % fn.frame)
|
||||
print("local variables area size: %8X" % fn.frsize)
|
||||
print("saved registers area size: %8X" % fn.frregs)
|
||||
print("bytes purged on return : %8X" % fn.argsize)
|
||||
print("frame pointer delta : %8X" % fn.fpd)
|
||||
|
||||
|
||||
def dump_parents(fn):
|
||||
"dump parents of a function tail"
|
||||
assert ida_funcs.is_func_tail(fn)
|
||||
print("owner function: %08X" % fn.owner)
|
||||
print("tail has %d referers" % fn.refqty)
|
||||
for i in range(fn.refqty):
|
||||
print(" referer %i: %08X" % (i, fn.referers[i]))
|
||||
|
||||
|
||||
def dump_func_info(ea):
|
||||
"dump info about function chunk at address 'ea'"
|
||||
pfn = ida_funcs.get_fchunk(ea)
|
||||
if pfn is None:
|
||||
print("No function at %08X!" % ea)
|
||||
return
|
||||
print("current chunk boundaries: %08X..%08X" % (pfn.start_ea, pfn.end_ea))
|
||||
dump_flags(pfn)
|
||||
if (ida_funcs.is_func_entry(pfn)):
|
||||
print ("This is an entry chunk")
|
||||
dump_tails(pfn)
|
||||
dump_frame(pfn)
|
||||
dump_regvars(pfn)
|
||||
dump_regargs(pfn)
|
||||
dump_stkpnts(pfn)
|
||||
elif (ida_funcs.is_func_tail(pfn)):
|
||||
print ("This is a tail chunk")
|
||||
dump_parents(pfn)
|
||||
|
||||
|
||||
ea = ida_kernwin.get_screen_ea()
|
||||
dump_func_info(ea)
|
||||
+41
-16
@@ -1,19 +1,44 @@
|
||||
from __future__ import print_function
|
||||
import idaapi
|
||||
"""
|
||||
summary: custom actions, with icons & tooltips
|
||||
|
||||
class SayHi(idaapi.action_handler_t):
|
||||
description:
|
||||
How to create user actions, that once created can be
|
||||
inserted in menus, toolbars, context menus, ...
|
||||
|
||||
Those actions, when triggered, will be passed a 'context'
|
||||
that contains some of the most frequently needed bits of
|
||||
information.
|
||||
|
||||
In addition, custom actions can determine when they want
|
||||
to be available (through their
|
||||
`ida_kernwin.action_handler_t.update` callback)
|
||||
|
||||
keywords: actions
|
||||
|
||||
see_also: add_hotkey
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import ida_kernwin
|
||||
|
||||
class SayHi(ida_kernwin.action_handler_t):
|
||||
def __init__(self, message):
|
||||
idaapi.action_handler_t.__init__(self)
|
||||
ida_kernwin.action_handler_t.__init__(self)
|
||||
self.message = message
|
||||
|
||||
def activate(self, ctx):
|
||||
print("Hi, %s" % (self.message))
|
||||
# print("context fields: %s" % dir(ctx))
|
||||
print(" cur_ea %08X" % ctx.cur_ea)
|
||||
print(" cur_value: %08X" % ctx.cur_value)
|
||||
print(" cur_extracted_ea %08X" % ctx.cur_extracted_ea)
|
||||
return 1
|
||||
|
||||
# You can implement update(), to inform IDA when:
|
||||
# * your action is enabled
|
||||
# * update() should queried again
|
||||
# E.g., returning 'idaapi.AST_ENABLE_FOR_WIDGET' will
|
||||
# E.g., returning 'ida_kernwin.AST_ENABLE_FOR_WIDGET' will
|
||||
# tell IDA that this action is available while the
|
||||
# user is in the current widget, and that update()
|
||||
# must be queried again once the user gives focus
|
||||
@@ -25,7 +50,7 @@ class SayHi(idaapi.action_handler_t):
|
||||
# querying update() anymore until the user has moved
|
||||
# to another view..
|
||||
def update(self, ctx):
|
||||
return idaapi.AST_ENABLE_FOR_WIDGET if ctx.widget_type == idaapi.BWN_DISASM else idaapi.AST_DISABLE_FOR_WIDGET
|
||||
return ida_kernwin.AST_ENABLE_FOR_WIDGET if ctx.widget_type == ida_kernwin.BWN_DISASM else ida_kernwin.AST_DISABLE_FOR_WIDGET
|
||||
|
||||
|
||||
print("Creating a custom icon from raw data!")
|
||||
@@ -49,12 +74,12 @@ icon_data = b"".join([
|
||||
b"\xF6\xC1\xED\x52\xB8\x77\xAB\x98\x3A\xCD\xC4\x73\x9D\x7C\x6F\xDE\xF9\xCF\x53\x0E\xFE\xA9\xCD\xAE\xB3\x87\xCE\x75\x35\x54\xE1\xD0\xCB\x47\x38\x39\x36\x88\xFF\x4D\xF8\x57\x41\x33",
|
||||
b"\xF1\xA4\x93\x0F\x00\x36\xAD\x3E\x4C\x6B\xC5\xC9\x5D\x77\x6A\x2F\xB4\x31\xA3\xC4\x40\x4F\x21\x0F\xD1\x4C\x3C\xE9\x2B\xE1\xF5\x0B\xD6\x90\xC8\x90\x4C\xE6\x35\xD0\xCC\x79\x5E\xFF",
|
||||
b"\x2E\xF8\x0B\x2F\x3D\xE5\xC3\x97\x06\xCF\xCF\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82"])
|
||||
act_icon = idaapi.load_custom_icon(data=icon_data, format="png")
|
||||
act_icon = ida_kernwin.load_custom_icon(data=icon_data, format="png")
|
||||
|
||||
hooks = None
|
||||
act_name = "example:add_action"
|
||||
|
||||
if idaapi.register_action(idaapi.action_desc_t(
|
||||
if ida_kernwin.register_action(ida_kernwin.action_desc_t(
|
||||
act_name, # Name. Acts as an ID. Must be unique.
|
||||
"Say hi!", # Label. That's what users see.
|
||||
SayHi("developer"), # Handler. Called when activated, and for updating
|
||||
@@ -64,13 +89,13 @@ if idaapi.register_action(idaapi.action_desc_t(
|
||||
print("Action registered. Attaching to menu.")
|
||||
|
||||
# Insert the action in the menu
|
||||
if idaapi.attach_action_to_menu("Edit/Export data", act_name, idaapi.SETMENU_APP):
|
||||
if ida_kernwin.attach_action_to_menu("Edit/Export data", act_name, ida_kernwin.SETMENU_APP):
|
||||
print("Attached to menu.")
|
||||
else:
|
||||
print("Failed attaching to menu.")
|
||||
|
||||
# Insert the action in a toolbar
|
||||
if idaapi.attach_action_to_toolbar("AnalysisToolBar", act_name):
|
||||
if ida_kernwin.attach_action_to_toolbar("AnalysisToolBar", act_name):
|
||||
print("Attached to toolbar.")
|
||||
else:
|
||||
print("Failed attaching to toolbar.")
|
||||
@@ -81,7 +106,7 @@ if idaapi.register_action(idaapi.action_desc_t(
|
||||
# To do that, we could in theory retrieve a reference to "IDA View-A", and
|
||||
# then request to "permanently" attach the action to it, using something
|
||||
# like this:
|
||||
# idaapi.attach_action_to_popup(ida_view_a, None, act_name, None)
|
||||
# ida_kernwin.attach_action_to_popup(ida_view_a, None, act_name, None)
|
||||
#
|
||||
# but alas, that won't do: widgets in IDA are very "volatile", and
|
||||
# can be deleted & re-created on some occasions (e.g., starting a
|
||||
@@ -92,17 +117,17 @@ if idaapi.register_action(idaapi.action_desc_t(
|
||||
# Instead, we can opt for a different method: attach our action on-the-fly,
|
||||
# when the popup for "IDA View-A" is being populated, right before
|
||||
# it is displayed.
|
||||
class Hooks(idaapi.UI_Hooks):
|
||||
class Hooks(ida_kernwin.UI_Hooks):
|
||||
def finish_populating_widget_popup(self, widget, popup):
|
||||
# We'll add our action to all "IDA View-*"s.
|
||||
# If we wanted to add it only to "IDA View-A", we could
|
||||
# also discriminate on the widget's title:
|
||||
#
|
||||
# if idaapi.get_widget_title(widget) == "IDA View-A":
|
||||
# if ida_kernwin.get_widget_title(widget) == "IDA View-A":
|
||||
# ...
|
||||
#
|
||||
if idaapi.get_widget_type(widget) == idaapi.BWN_DISASM:
|
||||
idaapi.attach_action_to_popup(widget, popup, act_name, None)
|
||||
if ida_kernwin.get_widget_type(widget) == ida_kernwin.BWN_DISASM:
|
||||
ida_kernwin.attach_action_to_popup(widget, popup, act_name, None)
|
||||
|
||||
hooks = Hooks()
|
||||
hooks.hook()
|
||||
@@ -110,7 +135,7 @@ else:
|
||||
print("Action found; unregistering.")
|
||||
# No need to call detach_action_from_menu(); it'll be
|
||||
# done automatically on destruction of the action.
|
||||
if idaapi.unregister_action(act_name):
|
||||
if ida_kernwin.unregister_action(act_name):
|
||||
print("Unregistered.")
|
||||
else:
|
||||
print("Failed to unregister action.")
|
||||
|
||||
@@ -1,24 +1,37 @@
|
||||
"""
|
||||
summary: triggering bits of code by pressing a shortcut
|
||||
|
||||
description:
|
||||
`ida_kernwin.add_hotkey` is a simpler, but much less flexible
|
||||
alternative to `ida_kernwin.register_action` (though it does
|
||||
use the same mechanism under the hood.)
|
||||
|
||||
It's particularly useful during prototyping, but note that the
|
||||
actions that are created cannot be inserted in menus, toolbars
|
||||
or cannot provide a custom `ida_kernwin.action_handler_t.update`
|
||||
callback.
|
||||
|
||||
keywords: actions
|
||||
|
||||
see_also: actions
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
#---------------------------------------------------------------------
|
||||
# This script demonstrates the usage of hotkeys.
|
||||
#
|
||||
#
|
||||
# Author: IDAPython team
|
||||
#---------------------------------------------------------------------
|
||||
import idaapi
|
||||
|
||||
import ida_kernwin
|
||||
|
||||
def hotkey_pressed():
|
||||
print("hotkey pressed!")
|
||||
|
||||
try:
|
||||
hotkey_ctx
|
||||
if idaapi.del_hotkey(hotkey_ctx):
|
||||
if ida_kernwin.del_hotkey(hotkey_ctx):
|
||||
print("Hotkey unregistered!")
|
||||
del hotkey_ctx
|
||||
else:
|
||||
print("Failed to delete hotkey!")
|
||||
except:
|
||||
hotkey_ctx = idaapi.add_hotkey("Shift-A", hotkey_pressed)
|
||||
hotkey_ctx = ida_kernwin.add_hotkey("Shift-A", hotkey_pressed)
|
||||
if hotkey_ctx is None:
|
||||
print("Failed to register hotkey!")
|
||||
del hotkey_ctx
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
from __future__ import print_function
|
||||
#---------------------------------------------------------------------
|
||||
# This script demonstrates the usage of hotkeys.
|
||||
#
|
||||
# Note: Hotkeys only work with the GUI version of IDA and not in
|
||||
# text mode.
|
||||
#
|
||||
# Author: Gergely Erdelyi <gergely.erdelyi@d-dome.net>
|
||||
#---------------------------------------------------------------------
|
||||
import idaapi
|
||||
|
||||
def foo():
|
||||
print("Hotkey activated!")
|
||||
|
||||
# IDA binds hotkeys to IDC functions so a trampoline IDC function
|
||||
# must be created
|
||||
idaapi.compile_idc_text('static key_2() { RunPythonStatement("foo()"); }')
|
||||
# Add the hotkey
|
||||
add_idc_hotkey("2", 'key_2')
|
||||
|
||||
# Press 2 to activate foo()
|
||||
|
||||
# The hotkey can be removed with
|
||||
# del_idc_hotkey('2')
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
"""
|
||||
summary: triggering bits of code by pressing a shortcut (older version)
|
||||
|
||||
description:
|
||||
This is a somewhat ancient way of registering actions & binding
|
||||
shortcuts. It's still here for reference, but "fresher" alternatives
|
||||
should be preferred.
|
||||
|
||||
keywords: actions
|
||||
|
||||
see_also: actions, add_hotkey
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import ida_expr
|
||||
import ida_kernwin
|
||||
|
||||
def say_hi():
|
||||
print("Hotkey activated!")
|
||||
|
||||
# IDA binds hotkeys to IDC functions so a trampoline IDC function must be created
|
||||
ida_expr.compile_idc_text('static key_2() { RunPythonStatement("say_hi()"); }')
|
||||
|
||||
# Add the hotkey
|
||||
ida_kernwin.add_idc_hotkey("2", 'key_2')
|
||||
|
||||
# Press 2 to activate foo()
|
||||
|
||||
# The hotkey can be removed with
|
||||
# ida_kernwin.del_idc_hotkey('2')
|
||||
|
||||
@@ -1,3 +1,28 @@
|
||||
"""
|
||||
summary: better integrating custom widgets in the desktop layout
|
||||
|
||||
description:
|
||||
This is an example demonstrating how one can create widgets from a plugin,
|
||||
and have them re-created automatically at IDA startup-time or at desktop load-time.
|
||||
|
||||
This example should be placed in the 'plugins' directory of the
|
||||
IDA installation, for it to work.
|
||||
|
||||
There are 2 ways to use this example:
|
||||
1) reloading an IDB, where the widget was opened
|
||||
- open the widget ('View > Open subview > ...')
|
||||
- save this IDB, and close IDA
|
||||
- restart IDA with this IDB
|
||||
=> the widget will be visible
|
||||
|
||||
2) reloading a desktop, where the widget was opened
|
||||
- open the widget ('View > Open subview > ...')
|
||||
- save the desktop ('Windows > Save desktop...') under, say, the name 'with_auto'
|
||||
- start another IDA instance with some IDB, and load that desktop
|
||||
=> the widget will be visible
|
||||
|
||||
keywords: desktop
|
||||
"""
|
||||
|
||||
import ida_idaapi
|
||||
import ida_kernwin
|
||||
@@ -13,26 +38,7 @@ class auto_inst_t(ida_kernwin.simplecustviewer_t):
|
||||
if not ida_kernwin.simplecustviewer_t.Create(self, title):
|
||||
return False
|
||||
|
||||
text = r"""
|
||||
This is an example demonstrating how one can create widgets from a plugin,
|
||||
and have them re-created automatically at IDA startup-time or at desktop load-time.
|
||||
|
||||
This example should be placed in the 'plugins' directory of the
|
||||
IDA installation, for it to work.
|
||||
|
||||
There are 2 ways to use this example:
|
||||
1) reloading an IDB, where the widget was opened
|
||||
- open the widget ('View > Open subview > """ + title + """')
|
||||
- save this IDB, and close IDA
|
||||
- restart IDA with this IDB
|
||||
=> the widget will be visible
|
||||
|
||||
2) reloading a desktop, where the widget was opened
|
||||
- open the widget ('View > Open subview > """ + title + """')
|
||||
- save the desktop ('Windows > Save desktop...') under, say, the name 'with_auto'
|
||||
- start another IDA instance with some IDB, and load that desktop
|
||||
=> the widget will be visible
|
||||
"""
|
||||
text = __doc__
|
||||
for l in text.split("\n"):
|
||||
self.AddLine(l)
|
||||
return True
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
"""
|
||||
summary: showcasing `ida_bytes.bin_search`
|
||||
|
||||
description:
|
||||
IDAPython's ida_bytes.bin_search function is pretty powerful,
|
||||
but can be tough to figure out at first. This example introduces
|
||||
|
||||
* `ida_bytes.bin_search`, and
|
||||
* `ida_bytes.parse_binpat_str`
|
||||
|
||||
in order to implement a simple replacement for the
|
||||
'Search > Sequence of bytes...' dialog, that lets users
|
||||
search for sequences of bytes that compose string literals
|
||||
in the binary file (either in the default 1-byte-per-char
|
||||
encoding, or as UTF-16.)
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
|
||||
import ida_kernwin
|
||||
import ida_bytes
|
||||
import ida_ida
|
||||
import ida_idaapi
|
||||
import ida_nalt
|
||||
|
||||
class search_strlit_form_t(ida_kernwin.Form):
|
||||
def __init__(self):
|
||||
ida_kernwin.Form.__init__(
|
||||
self,
|
||||
r"""Please enter string literal
|
||||
|
||||
<Text: {Text}>
|
||||
<#UTF16-BE if file is big-endian, UTF16-LE otherwise#As UTF-16: {UTF16}>{Encoding}>
|
||||
""",
|
||||
{
|
||||
"Text" : ida_kernwin.Form.StringInput(),
|
||||
"Encoding" : ida_kernwin.Form.ChkGroupControl(("UTF16",)),
|
||||
})
|
||||
|
||||
class search_strlit_ah_t(ida_kernwin.action_handler_t):
|
||||
def __init__(self):
|
||||
ida_kernwin.action_handler_t.__init__(self)
|
||||
|
||||
def activate(self, ctx):
|
||||
f = search_strlit_form_t()
|
||||
f, args = f.Compile()
|
||||
ok = f.Execute()
|
||||
if ok:
|
||||
current_ea = ida_kernwin.get_screen_ea()
|
||||
patterns = ida_bytes.compiled_binpat_vec_t()
|
||||
encoding = ida_nalt.get_default_encoding_idx(
|
||||
ida_nalt.BPU_2B if f.Encoding.value else ida_nalt.BPU_1B)
|
||||
# string literals must be quoted. That's how parse_binpat_str
|
||||
# recognizes them (we want to be careful though: the user
|
||||
# might type in something like 'L"hello"', which should
|
||||
# decode to the IDB-specific wide-char set of bytes)
|
||||
text = f.Text.value
|
||||
if text.find('"') < 0:
|
||||
text = '"%s"' % text
|
||||
err = ida_bytes.parse_binpat_str(
|
||||
patterns,
|
||||
current_ea,
|
||||
text,
|
||||
10, # radix (not that it matters though, since we're all about string literals)
|
||||
encoding)
|
||||
if not err:
|
||||
ea = ida_bytes.bin_search(
|
||||
current_ea,
|
||||
ida_ida.inf_get_max_ea(),
|
||||
patterns,
|
||||
ida_bytes.BIN_SEARCH_FORWARD
|
||||
| ida_bytes.BIN_SEARCH_NOBREAK
|
||||
| ida_bytes.BIN_SEARCH_NOSHOW)
|
||||
ok = ea != ida_idaapi.BADADDR
|
||||
if ok:
|
||||
ida_kernwin.jumpto(ea)
|
||||
else:
|
||||
print("Failed parsing binary pattern: \"%s\"" % err)
|
||||
return ok
|
||||
|
||||
def update(self, ctx):
|
||||
return ida_kernwin.AST_ENABLE_FOR_WIDGET \
|
||||
if ctx.widget_type == ida_kernwin.BWN_DISASM \
|
||||
else ida_kernwin.AST_DISABLE_FOR_WIDGET
|
||||
|
||||
|
||||
ACTION_NAME = "bin_search:search"
|
||||
ACTION_SHORTCUT = "Ctrl+Shift+S"
|
||||
|
||||
if ida_kernwin.register_action(
|
||||
ida_kernwin.action_desc_t(
|
||||
ACTION_NAME,
|
||||
"Search for string literal",
|
||||
search_strlit_ah_t(),
|
||||
ACTION_SHORTCUT)):
|
||||
print("Please use \"%s\" to search for string literals" % ACTION_SHORTCUT)
|
||||
@@ -0,0 +1,34 @@
|
||||
"""
|
||||
summary: change background colours
|
||||
|
||||
description:
|
||||
This illustrates the setting/retrieval of background colours
|
||||
using the IDC wrappers
|
||||
|
||||
In order to do so, we'll be assigning colors to specific ranges
|
||||
(item, function, or segment). Those will be persisted in the
|
||||
database.
|
||||
|
||||
category: disassembly
|
||||
|
||||
keywords: coloring, idc
|
||||
|
||||
see_also: colorize_disassembly_on_the_fly
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
|
||||
BG_BLUE = 0xc02020
|
||||
BG_GREEN = 0x208020
|
||||
BG_RED = 0x2020c0
|
||||
|
||||
import idc
|
||||
|
||||
ea = idc.here()
|
||||
idc.set_color(ea, idc.CIC_SEGM, BG_BLUE)
|
||||
idc.set_color(ea, idc.CIC_FUNC, BG_GREEN)
|
||||
idc.set_color(ea, idc.CIC_ITEM, BG_RED)
|
||||
print("Segment: %x" % idc.get_color(ea, idc.CIC_SEGM))
|
||||
print("Function: %x" % idc.get_color(ea, idc.CIC_FUNC))
|
||||
print("Item: %x" % idc.get_color(ea, idc.CIC_ITEM))
|
||||
@@ -0,0 +1,136 @@
|
||||
"""
|
||||
summary: an easy-to-use way to colorize lines
|
||||
|
||||
description:
|
||||
This builds upon the `ida_kernwin.UI_Hooks.get_lines_rendering_info`
|
||||
feature, to provide a quick & easy way to colorize disassembly
|
||||
lines.
|
||||
|
||||
Contrary to @colorize_disassembly, the coloring is not persisted in
|
||||
the database, and will therefore be lost after the session.
|
||||
|
||||
By triggering the action multiple times, the user can "carousel"
|
||||
across 4 predefined colors (and return to the "no color" state.)
|
||||
|
||||
keywords: coloring
|
||||
|
||||
see_also: colorize_disassembly
|
||||
"""
|
||||
|
||||
import ida_kernwin
|
||||
import ida_moves
|
||||
|
||||
class on_the_fly_coloring_hooks_t(ida_kernwin.UI_Hooks):
|
||||
|
||||
# We'll offer the users the ability to carousel around the
|
||||
# following colors. Well, note that these are in fact not
|
||||
# colors, but rather color "keys": each theme might have its
|
||||
# own values for those.
|
||||
AVAILABLE_COLORS = [
|
||||
ida_kernwin.CK_EXTRA5,
|
||||
ida_kernwin.CK_EXTRA6,
|
||||
ida_kernwin.CK_EXTRA7,
|
||||
ida_kernwin.CK_EXTRA8,
|
||||
]
|
||||
|
||||
def __init__(self):
|
||||
ida_kernwin.UI_Hooks.__init__(self)
|
||||
|
||||
# Each view can have on-the-fly coloring.
|
||||
# We'll store the custom colors keyed on the widget's title
|
||||
self.by_widget = {}
|
||||
|
||||
def get_lines_rendering_info(self, out, widget, rin):
|
||||
"""
|
||||
Called by IDA, at rendering-time.
|
||||
|
||||
We'll look in our set of marked lines, and for those that are
|
||||
found, will produce additional rendering information for IDA
|
||||
to use.
|
||||
"""
|
||||
title = ida_kernwin.get_widget_title(widget)
|
||||
assigned = self.by_widget.get(title, None)
|
||||
if assigned is not None:
|
||||
for section_lines in rin.sections_lines:
|
||||
for line in section_lines:
|
||||
for loc, color in assigned:
|
||||
if self._same_lines(widget, line.at, loc.place()):
|
||||
e = ida_kernwin.line_rendering_output_entry_t(line)
|
||||
e.bg_color = color
|
||||
out.entries.push_back(e)
|
||||
|
||||
def _same_lines(self, viewer, p0, p1):
|
||||
return ida_kernwin.get_custom_viewer_place_xcoord(viewer, p0, p1) != -1
|
||||
|
||||
def _find_loc_index(self, viewer, assigned, loc):
|
||||
for idx, tpl in enumerate(assigned):
|
||||
_loc = tpl[0]
|
||||
if self._same_lines(viewer, loc.place(), _loc.place()):
|
||||
return idx
|
||||
return -1
|
||||
|
||||
def carousel_color(self, viewer, title):
|
||||
"""
|
||||
This performs the work of iterating across the available
|
||||
colors (and the 'no-color' state.)
|
||||
"""
|
||||
loc = ida_moves.lochist_entry_t()
|
||||
if ida_kernwin.get_custom_viewer_location(loc, viewer):
|
||||
assigned = self.by_widget.get(title, [])
|
||||
new_color = None
|
||||
|
||||
idx = self._find_loc_index(viewer, assigned, loc)
|
||||
if idx > -1:
|
||||
prev_color = assigned[idx][1]
|
||||
prev_color_idx = self.AVAILABLE_COLORS.index(prev_color)
|
||||
new_color = None \
|
||||
if prev_color_idx >= (len(self.AVAILABLE_COLORS) - 1) \
|
||||
else self.AVAILABLE_COLORS[prev_color_idx + 1]
|
||||
else:
|
||||
new_color = self.AVAILABLE_COLORS[0]
|
||||
|
||||
if idx > -1:
|
||||
del assigned[idx]
|
||||
if new_color is not None:
|
||||
assigned.append((loc, new_color))
|
||||
|
||||
if assigned:
|
||||
self.by_widget[title] = assigned
|
||||
else:
|
||||
if title in self.by_widget:
|
||||
del self.by_widget[title]
|
||||
|
||||
|
||||
class carousel_color_ah_t():
|
||||
"""
|
||||
The action that will be invoked by IDA when the user
|
||||
activates its shortcut.
|
||||
"""
|
||||
def __init__(self, hooks):
|
||||
self.hooks = hooks
|
||||
|
||||
def activate(self, ctx):
|
||||
v = ida_kernwin.get_current_viewer()
|
||||
if v:
|
||||
self.hooks.carousel_color(v, ctx.widget_title)
|
||||
return 1 # will cause the widget to redraw
|
||||
|
||||
def update(self, ctx):
|
||||
return ida_kernwin.AST_ENABLE_FOR_WIDGET \
|
||||
if ida_kernwin.get_current_viewer() \
|
||||
else ida_kernwin.AST_DISABLE_FOR_WIDGET
|
||||
|
||||
|
||||
ACTION_NAME = "example:colorize_disassembly_on_the_fly"
|
||||
ACTION_LABEL = "Pick line color"
|
||||
ACTION_SHORTCUT = "!"
|
||||
ACTION_HELP = "Press %s to carousel around available colors (or remove a previously-set color)" % ACTION_SHORTCUT
|
||||
|
||||
otf_coloring = on_the_fly_coloring_hooks_t()
|
||||
if ida_kernwin.register_action(ida_kernwin.action_desc_t(
|
||||
ACTION_NAME,
|
||||
ACTION_LABEL,
|
||||
carousel_color_ah_t(otf_coloring),
|
||||
ACTION_SHORTCUT)):
|
||||
print("Registered action \"%s\". %s" % (ACTION_LABEL, ACTION_HELP))
|
||||
otf_coloring.hook()
|
||||
@@ -1,20 +0,0 @@
|
||||
from __future__ import print_function
|
||||
#---------------------------------------------------------------------
|
||||
# Colour test
|
||||
#
|
||||
# This script demonstrates the usage of background colours.
|
||||
#
|
||||
# Author: Gergely Erdelyi <gergely.erdelyi@d-dome.net>
|
||||
#---------------------------------------------------------------------
|
||||
|
||||
# Set the colour of the current segment to BLUE
|
||||
set_color(here(), CIC_SEGM, 0xc02020)
|
||||
# Set the colour of the current function to GREEN
|
||||
set_color(here(), CIC_FUNC, 0x208020)
|
||||
# Set the colour of the current item to RED
|
||||
set_color(here(), CIC_ITEM, 0x2020c0)
|
||||
|
||||
# Print the colours just set
|
||||
print("%x" % get_color(here(), CIC_SEGM))
|
||||
print("%x" % get_color(here(), CIC_FUNC))
|
||||
print("%x" % get_color(here(), CIC_ITEM))
|
||||
@@ -1,50 +1,68 @@
|
||||
"""
|
||||
summary: programmatically create & populate a structure
|
||||
|
||||
description:
|
||||
Usage of the API to create & populate a structure with
|
||||
members of different types.
|
||||
|
||||
author: Gergely Erdelyi (gergely.erdelyi@d-dome.net)
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
#---------------------------------------------------------------------
|
||||
# Structure test
|
||||
#
|
||||
# This script demonstrates how to create structures and populate them
|
||||
# with members of different types.
|
||||
#
|
||||
# Author: Gergely Erdelyi <gergely.erdelyi@d-dome.net>
|
||||
#---------------------------------------------------------------------
|
||||
from idaapi import stroffflag, offflag
|
||||
|
||||
sid = get_struc_id("mystr1")
|
||||
import ida_struct
|
||||
import ida_idaapi
|
||||
import ida_bytes
|
||||
import ida_nalt
|
||||
|
||||
import idc
|
||||
|
||||
sid = ida_struct.get_struc_id("mystr1")
|
||||
if sid != -1:
|
||||
del_struc(sid)
|
||||
sid = add_struc(-1, "mystr1", 0)
|
||||
idc.del_struc(sid)
|
||||
sid = ida_struct.add_struc(ida_idaapi.BADADDR, "mystr1", 0)
|
||||
print("%x" % sid)
|
||||
|
||||
# Test simple data types
|
||||
simple_types = [ FF_BYTE, FF_WORD, FF_DWORD, FF_QWORD, FF_TBYTE, FF_OWORD, FF_FLOAT, FF_DOUBLE, FF_PACKREAL ]
|
||||
simple_sizes = [ 1, 2, 4, 8, 10, 16, 4, 8, 10 ]
|
||||
|
||||
i = 0
|
||||
for t,nsize in zip(simple_types, simple_sizes):
|
||||
print("t%x:"% ((t|FF_DATA)&0xFFFFFFFF), add_struc_member(sid, "t%02d"%i, BADADDR, (t|FF_DATA )&0xFFFFFFFF, -1, nsize))
|
||||
i+=1
|
||||
simple_types_data = [
|
||||
(ida_bytes.FF_BYTE, 1),
|
||||
(ida_bytes.FF_WORD, 2),
|
||||
(ida_bytes.FF_DWORD, 4),
|
||||
(ida_bytes.FF_QWORD, 8),
|
||||
(ida_bytes.FF_TBYTE, 10),
|
||||
(ida_bytes.FF_OWORD, 16),
|
||||
(ida_bytes.FF_FLOAT, 4),
|
||||
(ida_bytes.FF_DOUBLE, 8),
|
||||
(ida_bytes.FF_PACKREAL, 10),
|
||||
]
|
||||
for i, tpl in enumerate(simple_types_data):
|
||||
t, nsize = tpl
|
||||
print("t%x:"% ((t|ida_bytes.FF_DATA) & 0xFFFFFFFF),
|
||||
idc.add_struc_member(sid, "t%02d"%i, ida_idaapi.BADADDR, (t|ida_bytes.FF_DATA )&0xFFFFFFFF, -1, nsize))
|
||||
|
||||
# Test ASCII type
|
||||
print("ASCII:", add_struc_member(sid, "tascii", -1, FF_STRLIT|FF_DATA, STRTYPE_C, 8))
|
||||
|
||||
# Test enum type - Add a defined enum name or load MACRO_WMI from a type library.
|
||||
#eid = get_enum("MACRO_WMI")
|
||||
#print("Enum:", add_struc_member(sid, "tenum", BADADDR, FF_0ENUM|FF_DATA|FF_DWORD, eid, 4))
|
||||
print("ASCII:", idc.add_struc_member(sid, "tascii", -1, ida_bytes.FF_STRLIT|ida_bytes.FF_DATA, ida_nalt.STRTYPE_C, 8))
|
||||
|
||||
# Test struc member type
|
||||
msid = get_struc_id("mystr2")
|
||||
msid = ida_struct.get_struc_id("mystr2")
|
||||
if msid != -1:
|
||||
del_struc(msid)
|
||||
msid = add_struc(-1, "mystr2", 0)
|
||||
print(add_struc_member(msid, "member1", -1, (FF_DWORD|FF_DATA )&0xFFFFFFFF, -1, 4))
|
||||
print(add_struc_member(msid, "member2", -1, (FF_DWORD|FF_DATA )&0xFFFFFFFF, -1, 4))
|
||||
idc.del_struc(msid)
|
||||
msid = idc.add_struc(-1, "mystr2", 0)
|
||||
print(idc.add_struc_member(msid, "member1", -1, (ida_bytes.FF_DWORD|ida_bytes.FF_DATA )&0xFFFFFFFF, -1, 4))
|
||||
print(idc.add_struc_member(msid, "member2", -1, (ida_bytes.FF_DWORD|ida_bytes.FF_DATA )&0xFFFFFFFF, -1, 4))
|
||||
|
||||
msize = get_struc_size(msid)
|
||||
print("Struct:", add_struc_member(sid, "tstruct", -1, FF_STRUCT|FF_DATA, msid, msize))
|
||||
print("Stroff:", add_struc_member(sid, "tstroff", -1, stroffflag()|FF_DWORD, msid, 4))
|
||||
msize = ida_struct.get_struc_size(msid)
|
||||
print("Struct:", idc.add_struc_member(sid, "tstruct", -1, ida_bytes.FF_STRUCT|ida_bytes.FF_DATA, msid, msize))
|
||||
print("Stroff:", idc.add_struc_member(sid, "tstroff", -1, ida_bytes.stroff_flag()|ida_bytes.FF_DWORD, msid, 4))
|
||||
|
||||
# Test offset types
|
||||
print("Offset:", add_struc_member(sid, "toffset", -1, offflag()|FF_DATA|FF_DWORD, 0, 4))
|
||||
print("Offset:", set_member_type(sid, 0, offflag()|FF_DATA|FF_DWORD, 0, 4))
|
||||
print("Offset:", idc.add_struc_member(sid, "toffset", -1, ida_bytes.off_flag()|ida_bytes.FF_DATA|ida_bytes.FF_DWORD, 0, 4))
|
||||
print("Offset:", idc.set_member_type(sid, 0, ida_bytes.off_flag()|ida_bytes.FF_DATA|ida_bytes.FF_DWORD, 0, 4))
|
||||
|
||||
print("Done")
|
||||
|
||||
+36
-47
@@ -1,77 +1,65 @@
|
||||
"""
|
||||
summary: a custom command-line interpreter
|
||||
|
||||
description:
|
||||
Illustrates how one can add command-line interpreters to IDA
|
||||
|
||||
This custom interpreter doesn't actually run any code; it's
|
||||
there as a 'getting started'.
|
||||
It provides an example tab completion support.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
# -----------------------------------------------------------------------
|
||||
# This is an example illustrating how to implement a CLI
|
||||
# (c) Hex-Rays
|
||||
#
|
||||
from idaapi import NW_OPENIDB, NW_CLOSEIDB, NW_TERMIDA, NW_REMOVE, COLSTR, cli_t
|
||||
# A trivial example is also provided for tab completion. To try it,
|
||||
# type "bon" in the input field, and then press <Tab> multiple times.
|
||||
#
|
||||
# (c) Hex-Rays
|
||||
|
||||
class mycli_t(cli_t):
|
||||
import ida_kernwin
|
||||
import ida_idaapi
|
||||
|
||||
class mycli_t(ida_kernwin.cli_t):
|
||||
flags = 0
|
||||
sname = "pycli"
|
||||
lname = "Python CLI"
|
||||
hint = "pycli hint"
|
||||
|
||||
def OnExecuteLine(self, line):
|
||||
"""
|
||||
The user pressed Enter. The CLI is free to execute the line immediately or ask for more lines.
|
||||
|
||||
This callback is mandatory.
|
||||
|
||||
@param line: typed line(s)
|
||||
@return Boolean: True-executed line, False-ask for more lines
|
||||
"""
|
||||
print("OnExecute:", line)
|
||||
return True
|
||||
|
||||
def OnKeydown(self, line, x, sellen, vkey, shift):
|
||||
"""
|
||||
A keyboard key has been pressed
|
||||
This is a generic callback and the CLI is free to do whatever it wants.
|
||||
|
||||
This callback is optional.
|
||||
|
||||
@param line: current input line
|
||||
@param x: current x coordinate of the cursor
|
||||
@param sellen: current selection length (usually 0)
|
||||
@param vkey: virtual key code. if the key has been handled, it should be returned as zero
|
||||
@param shift: shift state
|
||||
|
||||
@return:
|
||||
None - Nothing was changed
|
||||
tuple(line, x, sellen, vkey): if either of the input line or the x coordinate or the selection length has been modified.
|
||||
It is possible to return a tuple with None elements to preserve old values. Example: tuple(new_line, None, None, None) or tuple(new_line)
|
||||
"""
|
||||
print("Onkeydown: line=%s x=%d sellen=%d vkey=%d shift=%d" % (line, x, sellen, vkey, shift))
|
||||
return None
|
||||
|
||||
completions = [
|
||||
"bonnie & clyde",
|
||||
"bonfire of the vanities",
|
||||
"bongiorno",
|
||||
]
|
||||
|
||||
def OnCompleteLine(self, prefix, n, line, prefix_start):
|
||||
"""
|
||||
The user pressed Tab. Find a completion number N for prefix PREFIX
|
||||
|
||||
This callback is optional.
|
||||
|
||||
@param prefix: Line prefix at prefix_start (string)
|
||||
@param n: completion number (int)
|
||||
@param line: the current line (string)
|
||||
@param prefix_start: the index where PREFIX starts in LINE (int)
|
||||
|
||||
@return: None if no completion could be generated otherwise a String with the completion suggestion
|
||||
"""
|
||||
print("OnCompleteLine: prefix=%s n=%d line=%s prefix_start=%d" % (prefix, n, line, prefix_start))
|
||||
if prefix == "bon":
|
||||
if n < len(self.completions):
|
||||
return self.completions[n]
|
||||
return None
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
def nw_handler(code, old=0):
|
||||
if code == NW_OPENIDB:
|
||||
if code == ida_idaapi.NW_OPENIDB:
|
||||
print("nw_handler(): installing CLI")
|
||||
mycli.register()
|
||||
elif code == NW_CLOSEIDB:
|
||||
elif code == ida_idaapi.NW_CLOSEIDB:
|
||||
print("nw_handler(): removing CLI")
|
||||
mycli.unregister()
|
||||
elif code == NW_TERMIDA:
|
||||
elif code == ida_idaapi.NW_TERMIDA:
|
||||
print("nw_handler(): uninstalled nw handler")
|
||||
idaapi.notify_when(NW_TERMIDA | NW_OPENIDB | NW_CLOSEIDB | NW_REMOVE, nw_handler)
|
||||
when = ida_idaapi.NW_TERMIDA | ida_idaapi.NW_OPENIDB | ida_idaapi.NW_CLOSEIDB | ida_idaapi.NW_REMOVE
|
||||
ida_idaapi.notify_when(when, nw_handler)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
@@ -82,7 +70,7 @@ try:
|
||||
mycli.unregister()
|
||||
del mycli
|
||||
# remove previous handler
|
||||
nw_handler(NW_TERMIDA)
|
||||
nw_handler(ida_idaapi.NW_TERMIDA)
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
@@ -92,7 +80,8 @@ finally:
|
||||
if mycli.register():
|
||||
print("CLI installed")
|
||||
# install new handler
|
||||
idaapi.notify_when(NW_TERMIDA | NW_OPENIDB | NW_CLOSEIDB, nw_handler)
|
||||
when = ida_idaapi.NW_TERMIDA | ida_idaapi.NW_OPENIDB | ida_idaapi.NW_CLOSEIDB
|
||||
ida_idaapi.notify_when(when, nw_handler)
|
||||
else:
|
||||
del mycli
|
||||
print("Failed to install CLI")
|
||||
|
||||
@@ -1,9 +1,24 @@
|
||||
"""
|
||||
summary: using custom data types & printers
|
||||
|
||||
description:
|
||||
IDA can be extended to support certain data types that it
|
||||
does not know about out-of-the-box.
|
||||
|
||||
A 'custom data type' provide information about the type &
|
||||
size of a piece of data, while a 'custom data format' is in
|
||||
charge of formatting that data (there can be more than
|
||||
one format for a specific 'custom data type'.)
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
# -----------------------------------------------------------------------
|
||||
# This is an example illustrating how to use custom data types in Python
|
||||
# (c) Hex-Rays
|
||||
#
|
||||
from idaapi import data_type_t, data_format_t, NW_OPENIDB, NW_CLOSEIDB, NW_TERMIDA, NW_REMOVE, COLSTR
|
||||
|
||||
import ida_bytes
|
||||
import ida_idaapi
|
||||
import ida_lines
|
||||
import ida_struct
|
||||
import ida_netnode
|
||||
import ida_nalt
|
||||
|
||||
import sys
|
||||
import struct
|
||||
@@ -11,9 +26,9 @@ import ctypes
|
||||
import platform
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
class pascal_data_type(data_type_t):
|
||||
class pascal_data_type(ida_bytes.data_type_t):
|
||||
def __init__(self):
|
||||
data_type_t.__init__(
|
||||
ida_bytes.data_type_t.__init__(
|
||||
self,
|
||||
"py_pascal_string",
|
||||
2,
|
||||
@@ -24,11 +39,11 @@ class pascal_data_type(data_type_t):
|
||||
def calc_item_size(self, ea, maxsize):
|
||||
# Custom data types may be used in structure definitions. If this case
|
||||
# ea is a member id. Check for this situation and return 1
|
||||
if idaapi.is_member_id(ea):
|
||||
if ida_struct.is_member_id(ea):
|
||||
return 1
|
||||
|
||||
# get the length byte
|
||||
n = idaapi.get_byte(ea)
|
||||
n = ida_bytes.get_byte(ea)
|
||||
|
||||
# string too big?
|
||||
if n > maxsize:
|
||||
@@ -36,10 +51,10 @@ class pascal_data_type(data_type_t):
|
||||
# ok, accept the string
|
||||
return n + 1
|
||||
|
||||
class pascal_data_format(data_format_t):
|
||||
class pascal_data_format(ida_bytes.data_format_t):
|
||||
FORMAT_NAME = "py_pascal_string_pstr"
|
||||
def __init__(self):
|
||||
data_format_t.__init__(
|
||||
ida_bytes.data_format_t.__init__(
|
||||
self,
|
||||
pascal_data_format.FORMAT_NAME)
|
||||
|
||||
@@ -57,7 +72,7 @@ class pascal_data_format(data_format_t):
|
||||
return "".join(o)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
class simplevm_data_type(data_type_t):
|
||||
class simplevm_data_type(ida_bytes.data_type_t):
|
||||
ASM_KEYWORD = "svm_emit"
|
||||
def __init__(
|
||||
self,
|
||||
@@ -65,7 +80,7 @@ class simplevm_data_type(data_type_t):
|
||||
value_size=1,
|
||||
menu_name="SimpleVM",
|
||||
asm_keyword=ASM_KEYWORD):
|
||||
data_type_t.__init__(
|
||||
ida_bytes.data_type_t.__init__(
|
||||
self,
|
||||
name,
|
||||
value_size,
|
||||
@@ -74,22 +89,22 @@ class simplevm_data_type(data_type_t):
|
||||
asm_keyword)
|
||||
|
||||
def calc_item_size(self, ea, maxsize):
|
||||
if idaapi.is_member_id(ea):
|
||||
if ida_struct.is_member_id(ea):
|
||||
return 1
|
||||
# get the opcode and see if it has an imm
|
||||
n = 5 if (idaapi.get_byte(ea) & 3) == 0 else 1
|
||||
n = 5 if (ida_bytes.get_byte(ea) & 3) == 0 else 1
|
||||
# string too big?
|
||||
if n > maxsize:
|
||||
return 0
|
||||
# ok, accept
|
||||
return n
|
||||
|
||||
class simplevm_data_format(data_format_t):
|
||||
class simplevm_data_format(ida_bytes.data_format_t):
|
||||
def __init__(
|
||||
self,
|
||||
name="py_simple_vm_format",
|
||||
menu_name="SimpleVM"):
|
||||
data_format_t.__init__(
|
||||
ida_bytes.data_format_t.__init__(
|
||||
self,
|
||||
name,
|
||||
0,
|
||||
@@ -116,9 +131,9 @@ class simplevm_data_format(data_format_t):
|
||||
imm = None
|
||||
sz = 1
|
||||
text = "%s %s, %s" % (
|
||||
COLSTR(simplevm_data_format.INST[op], idaapi.SCOLOR_INSN),
|
||||
COLSTR(simplevm_data_format.REGS[r1], idaapi.SCOLOR_REG),
|
||||
COLSTR("0x%08X" % imm, idaapi.SCOLOR_NUMBER) if imm is not None else COLSTR(simplevm_data_format.REGS[r2], idaapi.SCOLOR_REG))
|
||||
ida_lines.COLSTR(simplevm_data_format.INST[op], ida_lines.SCOLOR_INSN),
|
||||
ida_lines.COLSTR(simplevm_data_format.REGS[r1], ida_lines.SCOLOR_REG),
|
||||
ida_lines.COLSTR("0x%08X" % imm, ida_lines.SCOLOR_NUMBER) if imm is not None else ida_lines.COLSTR(simplevm_data_format.REGS[r2], ida_lines.SCOLOR_REG))
|
||||
return (sz, text)
|
||||
|
||||
def printf(self, value, current_ea, operand_num, dtid):
|
||||
@@ -131,9 +146,9 @@ class simplevm_data_format(data_format_t):
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# This format will display DWORD values as MAKE_DWORD(0xHI, 0xLO)
|
||||
class makedword_data_format(data_format_t):
|
||||
class makedword_data_format(ida_bytes.data_format_t):
|
||||
def __init__(self):
|
||||
data_format_t.__init__(
|
||||
ida_bytes.data_format_t.__init__(
|
||||
self,
|
||||
"py_makedword",
|
||||
4,
|
||||
@@ -156,14 +171,14 @@ class makedword_data_format(data_format_t):
|
||||
#
|
||||
# The get_rsrc_string() is not optimal since it loads/unloads the
|
||||
# DLL each time for a new string. It can be improved in many ways.
|
||||
class rsrc_string_format(data_format_t):
|
||||
class rsrc_string_format(ida_bytes.data_format_t):
|
||||
def __init__(self):
|
||||
data_format_t.__init__(
|
||||
ida_bytes.data_format_t.__init__(
|
||||
self,
|
||||
"py_w32rsrcstring",
|
||||
1,
|
||||
"Resource string")
|
||||
self.cache_node = idaapi.netnode("$ py_w32rsrcstring", 0, 1)
|
||||
self.cache_node = ida_netnode.netnode("$ py_w32rsrcstring", 0, 1)
|
||||
|
||||
def get_rsrc_string(self, fn, id):
|
||||
"""
|
||||
@@ -188,8 +203,8 @@ class rsrc_string_format(data_format_t):
|
||||
# Not cached?
|
||||
if val == None:
|
||||
# Retrieve it
|
||||
num = idaapi.struct_unpack(value)
|
||||
val = self.get_rsrc_string(idaapi.get_input_file_path(), num)
|
||||
num = ida_idaapi.struct_unpack(value)
|
||||
val = self.get_rsrc_string(ida_nalt.get_input_file_path(), num)
|
||||
# Cache it
|
||||
self.cache_node.supset(current_ea, val)
|
||||
|
||||
@@ -197,7 +212,7 @@ class rsrc_string_format(data_format_t):
|
||||
if val == "" or val == "\x00":
|
||||
return None
|
||||
# Return the format
|
||||
return "RSRC_STR(\"%s\")" % COLSTR(val, idaapi.SCOLOR_IMPNAME)
|
||||
return "RSRC_STR(\"%s\")" % ida_lines.COLSTR(val, ida_lines.SCOLOR_IMPNAME)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Table of formats and types to be registered/unregistered
|
||||
@@ -219,21 +234,23 @@ except:
|
||||
# -----------------------------------------------------------------------
|
||||
def nw_handler(code, old=0):
|
||||
# delete notifications
|
||||
if code == NW_OPENIDB:
|
||||
if not idaapi.register_data_types_and_formats(new_formats):
|
||||
if code == ida_idaapi.NW_OPENIDB:
|
||||
if not ida_bytes.register_data_types_and_formats(new_formats):
|
||||
print("Failed to register types!")
|
||||
elif code == NW_CLOSEIDB:
|
||||
idaapi.unregister_data_types_and_formats(new_formats)
|
||||
elif code == NW_TERMIDA:
|
||||
idaapi.notify_when(NW_TERMIDA | NW_OPENIDB | NW_CLOSEIDB | NW_REMOVE, nw_handler)
|
||||
elif code == ida_idaapi.NW_CLOSEIDB:
|
||||
ida_bytes.unregister_data_types_and_formats(new_formats)
|
||||
elif code == ida_idaapi.NW_TERMIDA:
|
||||
f = ida_idaapi.NW_TERMIDA | ida_idaapi.NW_OPENIDB | ida_idaapi.NW_CLOSEIDB | ida_idaapi.NW_REMOVE
|
||||
ida_idaapi.notify_when(f, nw_handler)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Check if already installed
|
||||
if idaapi.find_custom_data_type(pascal_data_format.FORMAT_NAME) == -1:
|
||||
if not idaapi.register_data_types_and_formats(new_formats):
|
||||
if ida_bytes.find_custom_data_type(pascal_data_format.FORMAT_NAME) == -1:
|
||||
if not ida_bytes.register_data_types_and_formats(new_formats):
|
||||
print("Failed to register types!")
|
||||
else:
|
||||
idaapi.notify_when(NW_TERMIDA | NW_OPENIDB | NW_CLOSEIDB, nw_handler)
|
||||
f = ida_idaapi.NW_TERMIDA | ida_idaapi.NW_OPENIDB | ida_idaapi.NW_CLOSEIDB
|
||||
ida_idaapi.notify_when(f, nw_handler)
|
||||
print("Formats installed!")
|
||||
else:
|
||||
print("Formats already installed!")
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
"""
|
||||
summary: retrieve extra comments
|
||||
|
||||
description:
|
||||
Use the `ida_lines.get_extra_cmt` API to retrieve anterior
|
||||
and posterior extra comments.
|
||||
|
||||
This script registers two actions, that can be used to dump
|
||||
the previous and next extra comments.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import ida_lines
|
||||
import ida_kernwin
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
class dump_at_point_handler_t(ida_kernwin.action_handler_t):
|
||||
def __init__(self, anchor):
|
||||
ida_kernwin.action_handler_t.__init__(self)
|
||||
self.anchor = anchor
|
||||
|
||||
def activate(self, ctx):
|
||||
ea = ida_kernwin.get_screen_ea()
|
||||
index = self.anchor
|
||||
while True:
|
||||
cmt = ida_lines.get_extra_cmt(ea, index)
|
||||
if cmt is None:
|
||||
break
|
||||
print("Got: '%s'" % cmt)
|
||||
index += 1
|
||||
|
||||
def update(self, ctx):
|
||||
return ida_kernwin.AST_ENABLE_FOR_WIDGET \
|
||||
if ctx.widget_type == ida_kernwin.BWN_DISASM \
|
||||
else ida_kernwin.AST_DISABLE_FOR_WIDGET
|
||||
|
||||
@staticmethod
|
||||
def compose_action_name(v):
|
||||
return "dump_extra_comments:%s" % v
|
||||
|
||||
|
||||
# --------------------------------------------------------
|
||||
# action variants
|
||||
|
||||
class action_previous_handler_t(dump_at_point_handler_t):
|
||||
ACTION_LABEL = "previous"
|
||||
ACTION_SHORTCUT = "Ctrl+Shift+Y"
|
||||
|
||||
def __init__(self):
|
||||
super(action_previous_handler_t, self).__init__(ida_lines.E_PREV)
|
||||
|
||||
class action_next_handler_t(dump_at_point_handler_t):
|
||||
ACTION_LABEL = "next"
|
||||
ACTION_SHORTCUT = "Ctrl+Shift+Z"
|
||||
|
||||
def __init__(self):
|
||||
super(action_next_handler_t, self).__init__(ida_lines.E_NEXT)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# create actions (and attach them to IDA View-A's context menu if possible)
|
||||
widget_title = "IDA View-A"
|
||||
ida_view = ida_kernwin.find_widget(widget_title)
|
||||
|
||||
action_variants = [
|
||||
action_previous_handler_t,
|
||||
action_next_handler_t,
|
||||
]
|
||||
for variant in action_variants:
|
||||
actname = dump_at_point_handler_t.compose_action_name(variant.ACTION_LABEL)
|
||||
if ida_kernwin.unregister_action(actname):
|
||||
print("Unregistered previously-registered action \"%s\"" % actname)
|
||||
|
||||
desc = ida_kernwin.action_desc_t(
|
||||
actname,
|
||||
"Dump %s extra comments" % variant.ACTION_LABEL,
|
||||
variant(),
|
||||
variant.ACTION_SHORTCUT)
|
||||
if ida_kernwin.register_action(desc):
|
||||
print("Registered action \"%s\"" % actname)
|
||||
|
||||
if ida_view and ida_kernwin.attach_action_to_popup(ida_view, None, actname):
|
||||
print("Permanently attached action \"%s\" to \"%s\"" % (actname, widget_title))
|
||||
@@ -1,44 +1,69 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
summary: dump function flowchart
|
||||
|
||||
description:
|
||||
Dumps the current function's flowchart, using 2 methods:
|
||||
|
||||
* the low-level `ida_gdl.qflow_chart_t` type
|
||||
* the somewhat higher-level, and slightly more pythonic
|
||||
`ida_gdl.FlowChart` type.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import idaapi
|
||||
|
||||
import ida_gdl
|
||||
import ida_funcs
|
||||
import ida_kernwin
|
||||
|
||||
def out(p, msg):
|
||||
if p:
|
||||
print(msg)
|
||||
|
||||
def out_succ(p, start_ea, end_ea):
|
||||
out(p, " SUCC: %x - %x" % (start_ea, end_ea))
|
||||
|
||||
def out_pred(p, start_ea, end_ea):
|
||||
out(p, " PRED: %x - %x" % (start_ea, end_ea))
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Using raw IDAAPI
|
||||
def raw_main(p=True):
|
||||
f = idaapi.get_func(here())
|
||||
# Using ida_gdl.qflow_chart_t
|
||||
def using_qflow_chart_t(ea, p=True):
|
||||
f = ida_funcs.get_func(ea)
|
||||
if not f:
|
||||
return
|
||||
|
||||
q = idaapi.qflow_chart_t("The title", f, 0, 0, idaapi.FC_PREDS)
|
||||
for n in range(0, q.size()):
|
||||
q = ida_gdl.qflow_chart_t("The title", f, 0, 0, 0)
|
||||
for n in range(q.size()):
|
||||
b = q[n]
|
||||
if p:
|
||||
print("%x - %x [%d]:" % (b.start_ea, b.end_ea, n))
|
||||
out(p, "%x - %x [%d]:" % (b.start_ea, b.end_ea, n))
|
||||
for ns in range(q.nsucc(n)):
|
||||
b2 = q[q.succ(n, ns)]
|
||||
out_succ(p, b2.start_ea, b2.end_ea)
|
||||
|
||||
for ns in range(0, q.nsucc(n)):
|
||||
if p:
|
||||
print("SUCC: %d->%d" % (n, q.succ(n, ns)))
|
||||
|
||||
for ns in range(0, q.npred(n)):
|
||||
if p:
|
||||
print("PRED: %d->%d" % (n, q.pred(n, ns)))
|
||||
for ns in range(q.npred(n)):
|
||||
b2 = q[q.pred(n, ns)]
|
||||
out_pred(p, b2.start_ea, b2.end_ea)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Using the class
|
||||
def cls_main(p=True):
|
||||
f = idaapi.FlowChart(idaapi.get_func(here()))
|
||||
# Using ida_gdl.FlowChart
|
||||
def using_FlowChart(ea, p=True):
|
||||
f = ida_gdl.FlowChart(ida_funcs.get_func(ea))
|
||||
|
||||
for block in f:
|
||||
if p:
|
||||
print("%x - %x [%d]:" % (block.start_ea, block.end_ea, block.id))
|
||||
out(p, "%x - %x [%d]:" % (block.start_ea, block.end_ea, block.id))
|
||||
for succ_block in block.succs():
|
||||
if p:
|
||||
print(" %x - %x [%d]:" % (succ_block.start_ea, succ_block.end_ea, succ_block.id))
|
||||
out_succ(p, succ_block.start_ea, succ_block.end_ea)
|
||||
|
||||
for pred_block in block.preds():
|
||||
if p:
|
||||
print(" %x - %x [%d]:" % (pred_block.start_ea, pred_block.end_ea, pred_block.id))
|
||||
out_pred(p, pred_block.start_ea, pred_block.end_ea)
|
||||
|
||||
q = None
|
||||
f = None
|
||||
raw_main(False)
|
||||
cls_main(True)
|
||||
ea = ida_kernwin.get_screen_ea()
|
||||
|
||||
print(">>> Dumping flow chart using ida_gdl.qflow_chart_t")
|
||||
using_qflow_chart_t(ea)
|
||||
|
||||
print(">>> Dumping flow chart using the higher-level ida_gdl.FlowChart")
|
||||
using_FlowChart(ea)
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
"""
|
||||
summary: retrieve & dump current selection
|
||||
|
||||
description:
|
||||
Shows how to retrieve the selection from a listing
|
||||
widget ("IDA View-A", "Hex View-1", "Pseudocode-A", ...) as
|
||||
two "cursors", and from there retrieve (in fact, generate)
|
||||
the corresponding text.
|
||||
|
||||
After running this script:
|
||||
|
||||
* select some text in one of the listing widgets (i.e.,
|
||||
"IDA View-*", "Enums", "Structures", "Pseudocode-*")
|
||||
* press Ctrl+Shift+S to dump the selection
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import ida_kernwin
|
||||
import ida_lines
|
||||
|
||||
class dump_selection_handler_t(ida_kernwin.action_handler_t):
|
||||
def activate(self, ctx):
|
||||
if ctx.has_flag(ida_kernwin.ACF_HAS_SELECTION):
|
||||
tp0, tp1 = ctx.cur_sel._from, ctx.cur_sel.to
|
||||
ud = ida_kernwin.get_viewer_user_data(ctx.widget)
|
||||
lnar = ida_kernwin.linearray_t(ud)
|
||||
lnar.set_place(tp0.at)
|
||||
lines = []
|
||||
while True:
|
||||
cur_place = lnar.get_place()
|
||||
first_line_ref = ida_kernwin.l_compare2(cur_place, tp0.at, ud)
|
||||
last_line_ref = ida_kernwin.l_compare2(cur_place, tp1.at, ud)
|
||||
if last_line_ref > 0: # beyond last line
|
||||
break
|
||||
line = ida_lines.tag_remove(lnar.down())
|
||||
if last_line_ref == 0: # at last line
|
||||
line = line[0:tp1.x]
|
||||
elif first_line_ref == 0: # at first line
|
||||
line = ' ' * tp0.x + line[tp0.x:]
|
||||
lines.append(line)
|
||||
for line in lines:
|
||||
print(line)
|
||||
return 1
|
||||
|
||||
def update(self, ctx):
|
||||
ok_widgets = [
|
||||
ida_kernwin.BWN_DISASM,
|
||||
ida_kernwin.BWN_STRUCTS,
|
||||
ida_kernwin.BWN_ENUMS,
|
||||
ida_kernwin.BWN_PSEUDOCODE,
|
||||
]
|
||||
return ida_kernwin.AST_ENABLE_FOR_WIDGET \
|
||||
if ctx.widget_type in ok_widgets \
|
||||
else ida_kernwin.AST_DISABLE_FOR_WIDGET
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# create actions (and attach them to IDA View-A's context menu if possible)
|
||||
ACTION_NAME = "dump_selection"
|
||||
ACTION_SHORTCUT = "Ctrl+Shift+S"
|
||||
|
||||
if ida_kernwin.unregister_action(ACTION_NAME):
|
||||
print("Unregistered previously-registered action \"%s\"" % ACTION_NAME)
|
||||
|
||||
if ida_kernwin.register_action(
|
||||
ida_kernwin.action_desc_t(
|
||||
ACTION_NAME,
|
||||
"Dump selection",
|
||||
dump_selection_handler_t(),
|
||||
ACTION_SHORTCUT)):
|
||||
print("Registered action \"%s\"" % ACTION_NAME)
|
||||
+22
-16
@@ -1,21 +1,27 @@
|
||||
"""
|
||||
summary: add functions to the IDC runtime from IDAPython
|
||||
|
||||
description:
|
||||
You can add IDC functions to IDA, whose "body" consists of
|
||||
IDAPython statements!
|
||||
|
||||
We'll register a 'pow' function, available to all IDC code,
|
||||
that when invoked will call back into IDAPython, and execute
|
||||
the provided function body.
|
||||
|
||||
After running this script, try switching to the IDC interpreter
|
||||
(using the button on the lower-left corner of IDA) and executing
|
||||
`pow(3, 7)`
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
# -----------------------------------------------------------------------
|
||||
# This is an example illustrating how to extend IDC from Python
|
||||
# (c) Hex-Rays
|
||||
#
|
||||
from idaapi import add_idc_func
|
||||
|
||||
def py_power(n, e):
|
||||
return n ** e
|
||||
import ida_expr
|
||||
|
||||
desc = ext_idcfunc_t
|
||||
desc.name = "pow"
|
||||
desc.func = py_power,
|
||||
desc.args = (idaapi.VT_LONG, idaapi.VT_LONG),
|
||||
desc.defvals = ()
|
||||
desc.flags = 0
|
||||
ok = add_idc_func(desc)
|
||||
if ok:
|
||||
print("Now the pow() will be present IDC!")
|
||||
if ida_expr.add_idc_func(
|
||||
"pow",
|
||||
lambda n, e: n ** e,
|
||||
(ida_expr.VT_LONG, ida_expr.VT_LONG)):
|
||||
print("The pow() function is now available in IDC")
|
||||
else:
|
||||
print("Failed to register pow() IDC function")
|
||||
|
||||
@@ -1,19 +1,27 @@
|
||||
#---------------------------------------------------------------------
|
||||
# Example user initialisation script: idapythonrc.py
|
||||
#
|
||||
# Place this script to ~/.idapro/ or to
|
||||
# %APPDATA%\Hex-Rays\IDA Pro
|
||||
#---------------------------------------------------------------------
|
||||
import idaapi
|
||||
"""
|
||||
summary: code to be run right after IDAPython initialization
|
||||
|
||||
description:
|
||||
The `idapythonrc.py` file:
|
||||
|
||||
* %APPDATA%\Hex-Rays\IDA Pro\idapythonrc.py (on Windows)
|
||||
* ~/.idapro/idapythonrc.py (on Linux & Mac)
|
||||
|
||||
can contain any IDAPython code that will be run as soon as
|
||||
IDAPython is done successfully initializing.
|
||||
"""
|
||||
|
||||
# Add your favourite script to ScriptBox for easy access
|
||||
# scriptbox.addscript("/here/is/my/favourite/script.py")
|
||||
|
||||
# Uncomment if you want to set Python as default interpreter in IDA
|
||||
# idaapi.enable_extlang_python(True)
|
||||
# import ida_idaapi
|
||||
# ida_idaapi.enable_extlang_python(True)
|
||||
|
||||
# Disable the Python from interactive command-line
|
||||
# idaapi.enable_python_cli(False)
|
||||
# import ida_idaapi
|
||||
# ida_idaapi.enable_python_cli(False)
|
||||
|
||||
# Set the timeout for the script execution cancel dialog
|
||||
# idaapi.set_script_timeout(10)
|
||||
# import ida_idaapi
|
||||
# ida_idaapi.set_script_timeout(10)
|
||||
|
||||
@@ -1,41 +1,49 @@
|
||||
"""
|
||||
summary: inserting information into disassembly prefixes
|
||||
|
||||
description:
|
||||
By default, disassembly line prefixes contain segment + address
|
||||
information (e.g., '.text:08047718'), but it is possible to
|
||||
"inject" other bits of information in there, thanks to the
|
||||
`ida_lines.user_defined_prefix_t` helper type.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import idaapi
|
||||
|
||||
PREFIX = idaapi.SCOLOR_INV + ' ' + idaapi.SCOLOR_INV
|
||||
import ida_lines
|
||||
import ida_idaapi
|
||||
|
||||
class prefix_plugin_t(idaapi.plugin_t):
|
||||
flags = 0
|
||||
comment = "This is a user defined prefix sample plugin"
|
||||
help = "This is help"
|
||||
wanted_name = "user defined prefix"
|
||||
wanted_hotkey = ""
|
||||
|
||||
|
||||
def user_prefix(self, ea, lnnum, indent, line, bufsize):
|
||||
#print("ea=%x lnnum=%d indent=%d line=%s bufsize=%d" % (ea, lnnum, indent, line, bufsize))
|
||||
PREFIX = ida_lines.SCOLOR_INV + ' ' + ida_lines.SCOLOR_INV
|
||||
|
||||
class my_user_prefix_t(ida_lines.user_defined_prefix_t):
|
||||
def get_user_defined_prefix(self, ea, insn, lnnum, indent, line):
|
||||
if (ea % 2 == 0) and indent == -1:
|
||||
return PREFIX
|
||||
else:
|
||||
return ""
|
||||
|
||||
|
||||
class prefix_plugin_t(ida_idaapi.plugin_t):
|
||||
flags = 0
|
||||
comment = "This is a user defined prefix sample plugin"
|
||||
help = "This is help"
|
||||
wanted_name = "user defined prefix"
|
||||
wanted_hotkey = ""
|
||||
|
||||
def __init__(self):
|
||||
self.prefix = None
|
||||
|
||||
def init(self):
|
||||
self.prefix_installed = idaapi.set_user_defined_prefix(8, self.user_prefix)
|
||||
if self.prefix_installed:
|
||||
print("prefix installed")
|
||||
|
||||
return idaapi.PLUGIN_KEEP
|
||||
|
||||
self.prefix = my_user_prefix_t(8)
|
||||
print("prefix installed")
|
||||
return ida_idaapi.PLUGIN_KEEP
|
||||
|
||||
def run(self, arg):
|
||||
pass
|
||||
|
||||
|
||||
def term(self):
|
||||
if self.prefix_installed:
|
||||
idaapi.set_user_defined_prefix(0, None)
|
||||
print("prefix uninstalled!")
|
||||
self.prefix = None
|
||||
print("prefix uninstalled!")
|
||||
|
||||
|
||||
def PLUGIN_ENTRY():
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
"""
|
||||
summary: showcases (a few of) the iterators available on a function
|
||||
|
||||
description:
|
||||
This demonstrates how to use some of the iterators available on the func_t type.
|
||||
|
||||
This example will focus on:
|
||||
|
||||
* `func_t[.__iter__]`: the default iterator; iterates on instructions
|
||||
* `func_t.data_items`: iterate on data items contained within a function
|
||||
* `func_t.head_items`: iterate on 'heads' (i.e., addresses containing
|
||||
the start of an instruction, or a data item.
|
||||
* `func_t.addresses`: iterate on all addresses within function (code
|
||||
and data, beginning of an item or not)
|
||||
|
||||
Type `help(ida_funcs.func_t)` for a full list of iterators.
|
||||
|
||||
In addition, one can use:
|
||||
|
||||
* `func_tail_iterator_t`: iterate on all the chunks (including
|
||||
the main one) of the function
|
||||
* `func_parent_iterator_t`: iterate on all the parent functions,
|
||||
that include this chunk
|
||||
|
||||
keywords: funcs iterator
|
||||
"""
|
||||
|
||||
import ida_bytes
|
||||
import ida_kernwin
|
||||
import ida_funcs
|
||||
import ida_ua
|
||||
|
||||
class logger_t(object):
|
||||
|
||||
class section_t(object):
|
||||
def __init__(self, logger, header):
|
||||
self.logger = logger
|
||||
self.logger.log(header)
|
||||
def __enter__(self):
|
||||
self.logger.indent += 2
|
||||
return self
|
||||
def __exit__(self, tp, value, traceback):
|
||||
self.logger.indent -= 2
|
||||
if value:
|
||||
return False # Re-raise
|
||||
|
||||
def __init__(self):
|
||||
self.indent = 0
|
||||
|
||||
def log(self, *args):
|
||||
print(" " * self.indent + "".join(args))
|
||||
|
||||
def log_ea(self, ea):
|
||||
F = ida_bytes.get_flags(ea)
|
||||
parts = ["0x%08x" % ea, ": "]
|
||||
if ida_bytes.is_code(F):
|
||||
parts.append("instruction (%s)" % ida_ua.print_insn_mnem(ea))
|
||||
if ida_bytes.is_data(F):
|
||||
parts.append("data")
|
||||
if ida_bytes.is_tail(F):
|
||||
parts.append("tail")
|
||||
if ida_bytes.is_unknown(F):
|
||||
parts.append("unknown")
|
||||
if ida_funcs.get_func(ea) != ida_funcs.get_fchunk(ea):
|
||||
parts.append(" (in function chunk)")
|
||||
self.log(*parts)
|
||||
|
||||
def main():
|
||||
# Get current ea
|
||||
ea = ida_kernwin.get_screen_ea()
|
||||
|
||||
pfn = ida_funcs.get_func(ea)
|
||||
|
||||
if pfn is None:
|
||||
print("No function defined at 0x%x" % ea)
|
||||
return
|
||||
|
||||
func_name = ida_funcs.get_func_name(pfn.start_ea)
|
||||
logger = logger_t()
|
||||
logger.log("Function %s at 0x%x" % (func_name, ea))
|
||||
|
||||
with logger_t.section_t(logger, "Code items:"):
|
||||
for item in pfn:
|
||||
logger.log_ea(item)
|
||||
|
||||
with logger_t.section_t(logger, "'head' items:"):
|
||||
for item in pfn.head_items():
|
||||
logger.log_ea(item)
|
||||
|
||||
with logger_t.section_t(logger, "Addresses:"):
|
||||
for item in pfn.addresses():
|
||||
logger.log_ea(item)
|
||||
|
||||
with logger_t.section_t(logger, "Function chunks:"):
|
||||
for chunk in ida_funcs.func_tail_iterator_t(pfn):
|
||||
logger.log("%s chunk: 0x%08x..0x%08x" % (
|
||||
"Main" if chunk.start_ea == pfn.start_ea else "Tail",
|
||||
chunk.start_ea,
|
||||
chunk.end_ea))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,30 +1,33 @@
|
||||
"""
|
||||
summary: enumerate file imports
|
||||
|
||||
description:
|
||||
Using the API to enumerate file imports.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
# -----------------------------------------------------------------------
|
||||
# This is an example illustrating how to enumerate imports
|
||||
# (c) Hex-Rays
|
||||
#
|
||||
import idaapi
|
||||
|
||||
def imp_cb(ea, name, ord):
|
||||
if not name:
|
||||
print("%08x: ord#%d" % (ea, ord))
|
||||
else:
|
||||
print("%08x: %s (ord#%d)" % (ea, name, ord))
|
||||
# True -> Continue enumeration
|
||||
# False -> Stop enumeration
|
||||
return True
|
||||
import ida_nalt
|
||||
|
||||
nimps = idaapi.get_import_module_qty()
|
||||
nimps = ida_nalt.get_import_module_qty()
|
||||
|
||||
print("Found %d import(s)..." % nimps)
|
||||
|
||||
for i in range(0, nimps):
|
||||
name = idaapi.get_import_module_name(i)
|
||||
for i in range(nimps):
|
||||
name = ida_nalt.get_import_module_name(i)
|
||||
if not name:
|
||||
print("Failed to get import module name for #%d" % i)
|
||||
continue
|
||||
name = "<unnamed>"
|
||||
|
||||
print("Walking-> %s" % name)
|
||||
idaapi.enum_import_names(i, imp_cb)
|
||||
print("Walking imports for module %s" % name)
|
||||
def imp_cb(ea, name, ordinal):
|
||||
if not name:
|
||||
print("%08x: ordinal #%d" % (ea, ordinal))
|
||||
else:
|
||||
print("%08x: %s (ordinal #%d)" % (ea, name, ordinal))
|
||||
# True -> Continue enumeration
|
||||
# False -> Stop enumeration
|
||||
return True
|
||||
ida_nalt.enum_import_names(i, imp_cb)
|
||||
|
||||
print("All done...")
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
from __future__ import print_function
|
||||
# -------------------------------------------------------------------------
|
||||
# This is an example illustrating how to visit all patched bytes in Python
|
||||
# (c) Hex-Rays
|
||||
"""
|
||||
summary: enumerate patched bytes
|
||||
|
||||
import idaapi
|
||||
description:
|
||||
Using the API to iterate over all the places in the file,
|
||||
that were patched using IDA.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import ida_bytes
|
||||
import ida_idaapi
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
class patched_bytes_visitor(object):
|
||||
@@ -14,7 +20,7 @@ class patched_bytes_visitor(object):
|
||||
def __call__(self, ea, fpos, o, v, cnt=()):
|
||||
if fpos == -1:
|
||||
self.skip += 1
|
||||
print(" ea: %x o: %x v: %x...skipped" % (ea, fpos, o, v))
|
||||
print(" ea: %x o: %x v: %x...skipped" % (ea, o, v))
|
||||
else:
|
||||
self.patch += 1
|
||||
print(" ea: %x fpos: %x o: %x v: %x" % (ea, fpos, o, v))
|
||||
@@ -25,7 +31,7 @@ class patched_bytes_visitor(object):
|
||||
def main():
|
||||
print("Visiting all patched bytes:")
|
||||
v = patched_bytes_visitor()
|
||||
r = idaapi.visit_patched_bytes(0, idaapi.BADADDR, v)
|
||||
r = ida_bytes.visit_patched_bytes(0, ida_idaapi.BADADDR, v)
|
||||
if r != 0:
|
||||
print("visit_patched_bytes() returned %d" % r)
|
||||
else:
|
||||
@@ -34,4 +40,4 @@ def main():
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
main()
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
"""
|
||||
summary: enumerate problems
|
||||
|
||||
description:
|
||||
Using the API to list all problem[atic situation]s that IDA
|
||||
encountered during analysis.
|
||||
"""
|
||||
|
||||
import ida_ida
|
||||
import ida_idaapi
|
||||
import ida_problems
|
||||
|
||||
for ptype in [
|
||||
ida_problems.PR_NOBASE,
|
||||
ida_problems.PR_NONAME,
|
||||
ida_problems.PR_NOFOP,
|
||||
ida_problems.PR_NOCMT,
|
||||
ida_problems.PR_NOXREFS,
|
||||
ida_problems.PR_JUMP,
|
||||
ida_problems.PR_DISASM,
|
||||
ida_problems.PR_HEAD,
|
||||
ida_problems.PR_ILLADDR,
|
||||
ida_problems.PR_MANYLINES,
|
||||
ida_problems.PR_BADSTACK,
|
||||
ida_problems.PR_ATTN,
|
||||
ida_problems.PR_FINAL,
|
||||
ida_problems.PR_ROLLED,
|
||||
ida_problems.PR_COLLISION,
|
||||
ida_problems.PR_DECIMP,
|
||||
]:
|
||||
plistdesc = ida_problems.get_problem_name(ptype)
|
||||
ea = ida_ida.inf_get_min_ea()
|
||||
while True:
|
||||
ea = ida_problems.get_problem(ptype, ea+1)
|
||||
if ea == ida_idaapi.BADADDR:
|
||||
break
|
||||
print("0x%08x: %s" % (ea, plistdesc))
|
||||
@@ -1,3 +1,15 @@
|
||||
"""
|
||||
summary: list all functions (and xrefs) in segment
|
||||
|
||||
description:
|
||||
List all the functions in the current segment, as well as
|
||||
all the cross-references to them.
|
||||
|
||||
keywords: xrefs
|
||||
|
||||
see_also: list_segment_functions_using_idautils
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
#
|
||||
# Reference Lister
|
||||
@@ -6,36 +18,39 @@ from __future__ import print_function
|
||||
#
|
||||
# Implemented using direct IDA Plugin API calls
|
||||
#
|
||||
from idaapi import *
|
||||
|
||||
import ida_kernwin
|
||||
import ida_segment
|
||||
import ida_funcs
|
||||
import ida_xref
|
||||
import ida_idaapi
|
||||
|
||||
def main():
|
||||
# Get current ea
|
||||
ea = get_screen_ea()
|
||||
ea = ida_kernwin.get_screen_ea()
|
||||
|
||||
# Get segment class
|
||||
seg = getseg(ea)
|
||||
seg = ida_segment.getseg(ea)
|
||||
|
||||
# Loop from segment start to end
|
||||
func_ea = seg.startEA
|
||||
func_ea = seg.start_ea
|
||||
|
||||
# Get a function at the start of the segment (if any)
|
||||
func = get_func(func_ea)
|
||||
func = ida_funcs.get_func(func_ea)
|
||||
if func is None:
|
||||
# No function there, try to get the next one
|
||||
func = get_next_func(func_ea)
|
||||
func = ida_funcs.get_next_func(func_ea)
|
||||
|
||||
seg_end = seg.end_ea
|
||||
while func is not None and func.start_ea < seg_end:
|
||||
funcea = func.start_ea
|
||||
print("Function %s at 0x%x" % (get_func_name(funcea), funcea))
|
||||
print("Function %s at 0x%x" % (ida_funcs.get_func_name(funcea), funcea))
|
||||
|
||||
ref = get_first_cref_to(funcea)
|
||||
xb = ida_xref.xrefblk_t()
|
||||
for ref in xb.crefs_to(funcea):
|
||||
print(" called from %s(0x%x)" % (ida_funcs.get_func_name(ref), ref))
|
||||
|
||||
while ref != BADADDR:
|
||||
print(" called from %s(0x%x)" % (get_func_name(ref), ref))
|
||||
ref = get_next_cref_to(funcea, ref)
|
||||
|
||||
func = get_next_func(funcea)
|
||||
func = ida_funcs.get_next_func(funcea)
|
||||
|
||||
|
||||
main()
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
"""
|
||||
summary: list all functions (and xrefs) in segment
|
||||
|
||||
description:
|
||||
List all the functions in the current segment, as well as
|
||||
all the cross-references to them.
|
||||
|
||||
Contrary to @list_segment_functions, this uses the somewhat
|
||||
higher-level `idautils` module.
|
||||
|
||||
keywords: xrefs
|
||||
|
||||
see_also: list_segment_functions
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
#
|
||||
# Reference Lister
|
||||
@@ -6,23 +21,32 @@ from __future__ import print_function
|
||||
#
|
||||
# Implemented with the idautils module
|
||||
#
|
||||
from idautils import *
|
||||
|
||||
import ida_kernwin
|
||||
import ida_idaapi
|
||||
import ida_segment
|
||||
import ida_funcs
|
||||
|
||||
import idautils
|
||||
|
||||
def main():
|
||||
# Get current ea
|
||||
ea = get_screen_ea()
|
||||
if ea == idaapi.BADADDR:
|
||||
ea = ida_kernwin.get_screen_ea()
|
||||
if ea == ida_idaapi.BADADDR:
|
||||
print("Could not get get_screen_ea()")
|
||||
return
|
||||
|
||||
# Loop from start to end in the current segment
|
||||
for funcea in Functions(get_segm_start(ea), get_segm_end(ea)):
|
||||
print("Function %s at 0x%x" % (get_func_name(funcea), funcea))
|
||||
|
||||
# Find all code references to funcea
|
||||
for ref in CodeRefsTo(funcea, 1):
|
||||
print(" called from %s(0x%x)" % (get_func_name(ref), ref))
|
||||
seg = ida_segment.getseg(ea)
|
||||
if seg:
|
||||
# Loop from start to end in the current segment
|
||||
for funcea in idautils.Functions(seg.start_ea, seg.end_ea):
|
||||
print("Function %s at 0x%x" % (ida_funcs.get_func_name(funcea), funcea))
|
||||
|
||||
# Find all code references to funcea
|
||||
for ref in idautils.CodeRefsTo(funcea, 1):
|
||||
print(" called from %s(0x%x)" % (ida_funcs.get_func_name(ref), ref))
|
||||
else:
|
||||
print("Please position the cursor within a segment")
|
||||
|
||||
if __name__=='__main__':
|
||||
main()
|
||||
main()
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
"""
|
||||
summary: list all xrefs to a function stack variable
|
||||
|
||||
description:
|
||||
Contrary to (in-memory) data & code xrefs, retrieving stack variables
|
||||
xrefs requires a bit more work than just using ida_xref's first_to(),
|
||||
next_to() (or higher level utilities such as idautils.XrefsTo)
|
||||
|
||||
keywords: xrefs
|
||||
"""
|
||||
|
||||
ACTION_NAME = "list_stkvar_xrefs:list"
|
||||
ACTION_SHORTCUT = "Ctrl+Shift+F7"
|
||||
|
||||
import ida_bytes
|
||||
import ida_frame
|
||||
import ida_funcs
|
||||
import ida_ida
|
||||
import ida_kernwin
|
||||
import ida_struct
|
||||
import ida_ua
|
||||
|
||||
class list_stkvar_xrefs_ah_t(ida_kernwin.action_handler_t):
|
||||
def activate(self, ctx):
|
||||
cur_ea = ida_kernwin.get_screen_ea()
|
||||
pfn = ida_funcs.get_func(cur_ea)
|
||||
if pfn:
|
||||
v = ida_kernwin.get_current_viewer()
|
||||
result = ida_kernwin.get_highlight(v)
|
||||
if result:
|
||||
stkvar_name, _ = result
|
||||
frame = ida_frame.get_frame(cur_ea)
|
||||
sptr = ida_struct.get_struc(frame.id)
|
||||
mptr = ida_struct.get_member_by_name(sptr, stkvar_name)
|
||||
if mptr:
|
||||
for ea in pfn:
|
||||
F = ida_bytes.get_flags(ea)
|
||||
for n in range(ida_ida.UA_MAXOP):
|
||||
if not ida_bytes.is_stkvar(F, n):
|
||||
continue
|
||||
insn = ida_ua.insn_t()
|
||||
if not ida_ua.decode_insn(insn, ea):
|
||||
continue
|
||||
v = ida_frame.calc_stkvar_struc_offset(pfn, insn, n)
|
||||
if v >= mptr.soff and v < mptr.eoff:
|
||||
print("Found xref at 0x%08x, operand #%d" % (ea, n))
|
||||
else:
|
||||
print("No stack variable named \"%s\"" % stkvar_name)
|
||||
else:
|
||||
print("Please position the cursor within a function")
|
||||
|
||||
def update(self, ctx):
|
||||
return ida_kernwin.AST_ENABLE_FOR_WIDGET \
|
||||
if ctx.widget_type == ida_kernwin.BWN_DISASM \
|
||||
else ida_kernwin.AST_DISABLE_FOR_WIDGET
|
||||
|
||||
adesc = ida_kernwin.action_desc_t(
|
||||
ACTION_NAME,
|
||||
"List stack variable xrefs",
|
||||
list_stkvar_xrefs_ah_t(),
|
||||
ACTION_SHORTCUT)
|
||||
|
||||
if ida_kernwin.register_action(adesc):
|
||||
print("Action registered. Please press \"%s\" to use" % ACTION_SHORTCUT)
|
||||
@@ -1,10 +1,22 @@
|
||||
"""
|
||||
summary: retrieve the strings that are present in the IDB
|
||||
|
||||
description:
|
||||
This uses `idautils.Strings` to iterate over the string literals
|
||||
that are present in the IDB. Contrary to @show_selected_strings,
|
||||
this will not require that the "Strings" window is opened & available.
|
||||
|
||||
see_also: show_selected_strings
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import ida_nalt
|
||||
import idautils
|
||||
|
||||
s = idautils.Strings(False)
|
||||
s.setup(strtypes=Strings.STR_UNICODE | Strings.STR_C)
|
||||
s.setup(strtypes=[ida_nalt.STRTYPE_C, ida_nalt.STRTYPE_C_16])
|
||||
for i, v in enumerate(s):
|
||||
if v is None:
|
||||
print("Failed to retrieve string index %d" % i)
|
||||
else:
|
||||
print("%x: len=%d type=%d index=%d-> '%s'" % (v.ea, v.length, v.type, i, str(v)))
|
||||
print("%x: len=%d type=0x%x index=%d-> '%s'" % (v.ea, v.length, v.strtype, i, str(v)))
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
"""
|
||||
summary: decompile entire file
|
||||
|
||||
description:
|
||||
automate IDA to perform auto-analysis on a file and,
|
||||
once that is done, produce a .c file containing the
|
||||
decompilation of all the functions in that file.
|
||||
|
||||
Run like so:
|
||||
|
||||
ida -A "-S...path/to/produce_c_file.py" <binary-file>
|
||||
|
||||
where:
|
||||
|
||||
* -A instructs IDA to run in non-interactive mode
|
||||
* -S holds a path to the script to run (note this is a single token;
|
||||
there is no space between '-S' and its path.)
|
||||
"""
|
||||
|
||||
import ida_pro
|
||||
import ida_auto
|
||||
import ida_loader
|
||||
import ida_hexrays
|
||||
|
||||
# derive output file name
|
||||
idb_path = ida_loader.get_path(ida_loader.PATH_TYPE_IDB)
|
||||
c_path = "%s.c" % idb_path
|
||||
|
||||
ida_auto.auto_wait() # wait for end of auto-analysis
|
||||
ida_hexrays.decompile_many( # generate .c file
|
||||
c_path,
|
||||
None,
|
||||
ida_hexrays.VDRUN_NEWFILE
|
||||
|ida_hexrays.VDRUN_SILENT
|
||||
|ida_hexrays.VDRUN_MAYSTOP)
|
||||
|
||||
ida_pro.qexit(0)
|
||||
@@ -0,0 +1,42 @@
|
||||
"""
|
||||
summary: produce listing
|
||||
|
||||
description:
|
||||
automate IDA to perform auto-analysis on a file and,
|
||||
once that is done, produce a .lst file with the disassembly.
|
||||
|
||||
Run like so:
|
||||
|
||||
ida -A "-S...path/to/produce_lst_file.py" <binary-file>
|
||||
|
||||
where:
|
||||
|
||||
* -A instructs IDA to run in non-interactive mode
|
||||
* -S holds a path to the script to run (note this is a single token;
|
||||
there is no space between '-S' and its path.)
|
||||
"""
|
||||
|
||||
import ida_auto
|
||||
import ida_fpro
|
||||
import ida_ida
|
||||
import ida_loader
|
||||
import ida_pro
|
||||
|
||||
# derive output file name
|
||||
idb_path = ida_loader.get_path(ida_loader.PATH_TYPE_IDB)
|
||||
lst_path = "%s.lst" % idb_path
|
||||
|
||||
ida_auto.auto_wait() # wait for end of auto-analysis
|
||||
fptr = ida_fpro.qfile_t() # FILE * wrapper
|
||||
if fptr.open(lst_path, "wt"):
|
||||
try:
|
||||
ida_loader.gen_file( # generate .lst file
|
||||
ida_loader.OFILE_LST,
|
||||
fptr.get_fp(),
|
||||
ida_ida.inf_get_min_ea(),
|
||||
ida_ida.inf_get_max_ea(),
|
||||
0)
|
||||
finally:
|
||||
fptr.close()
|
||||
|
||||
ida_pro.qexit(0)
|
||||
@@ -1,15 +1,19 @@
|
||||
from __future__ import print_function
|
||||
# -------------------------------------------------------------------------
|
||||
# This is an example illustrating how to use timers
|
||||
# (c) Hex-Rays
|
||||
"""
|
||||
summary: using timers for delayed execution
|
||||
|
||||
import idaapi
|
||||
description:
|
||||
Register (possibly repeating) timers.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import ida_kernwin
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
class timercallback_t(object):
|
||||
def __init__(self):
|
||||
self.interval = 1000
|
||||
self.obj = idaapi.register_timer(self.interval, self)
|
||||
self.obj = ida_kernwin.register_timer(self.interval, self)
|
||||
if self.obj is None:
|
||||
raise RuntimeError("Failed to register timer")
|
||||
self.times = 5
|
||||
@@ -21,19 +25,19 @@ class timercallback_t(object):
|
||||
return -1 if self.times == 0 else self.interval
|
||||
|
||||
def __del__(self):
|
||||
print("Timer object disposed %s" % id(self))
|
||||
print("Timer object disposed %s" % self)
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
def main():
|
||||
try:
|
||||
t = timercallback_t()
|
||||
# No need to unregister the timer.
|
||||
# It will unregister itself in the callback when it returns -1
|
||||
# No need to unregister the timer.
|
||||
# It will unregister itself in the callback when it returns -1
|
||||
except Exception as e:
|
||||
print("Error: %s" % e)
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
main()
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
"""
|
||||
summary: execute existing actions programmatically
|
||||
|
||||
description:
|
||||
It's possible to invoke any action programmatically, by using
|
||||
either of those two:
|
||||
|
||||
* ida_kernwin.execute_ui_requests()
|
||||
* ida_kernwin.process_ui_action()
|
||||
|
||||
Ideally, this script should be run through the "File > Script file..."
|
||||
menu, so as to keep focus on "IDA View-A" and have the
|
||||
'ProcessUiActions' part work as intended.
|
||||
|
||||
keywords: actions
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
# -----------------------------------------------------------------------
|
||||
# This is an example illustrating how to use the execute_ui_requests()
|
||||
# and the idautils.ProcessUiActions()
|
||||
# (c) Hex-Rays
|
||||
#
|
||||
import idaapi
|
||||
import idautils
|
||||
import idc
|
||||
|
||||
import ida_kernwin
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
class __process_ui_actions_helper(object):
|
||||
@@ -34,9 +45,9 @@ class __process_ui_actions_helper(object):
|
||||
return False
|
||||
|
||||
# Execute one action
|
||||
idaapi.process_ui_action(
|
||||
self.__action_list[self.__idx],
|
||||
self.__flags)
|
||||
aname = self.__action_list[self.__idx]
|
||||
print("executing: %s (flags=0x%x)" % (aname, self.__flags))
|
||||
print("=> %s" % ida_kernwin.process_ui_action(aname, self.__flags))
|
||||
|
||||
# Move to next action
|
||||
self.__idx += 1
|
||||
@@ -55,7 +66,7 @@ def ProcessUiActions(actions, flags=0):
|
||||
|
||||
# Instantiate a helper
|
||||
helper = __process_ui_actions_helper(actions, flags)
|
||||
return False if len(helper) < 1 else idaapi.execute_ui_requests((helper,))
|
||||
return False if len(helper) < 1 else ida_kernwin.execute_ui_requests((helper,))
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
@@ -63,14 +74,15 @@ class print_req_t(object):
|
||||
def __init__(self, s):
|
||||
self.s = s
|
||||
def __call__(self):
|
||||
idaapi.msg("%s" % self.s)
|
||||
ida_kernwin.msg("%s" % self.s)
|
||||
return False # Don't reschedule
|
||||
|
||||
|
||||
|
||||
if idc.ask_yn(1,("HIDECANCEL\nDo you want to run execute_ui_requests() example?\n"
|
||||
"Press NO to execute ProcessUiActions() example\n")):
|
||||
idaapi.execute_ui_requests(
|
||||
(print_req_t("Hello"), print_req_t(" world\n")) )
|
||||
if ida_kernwin.ask_yn(
|
||||
1, ("HIDECANCEL\nDo you want to run execute_ui_requests() example?\n"
|
||||
"Press NO to execute ProcessUiActions() example\n")):
|
||||
ida_kernwin.execute_ui_requests(
|
||||
(print_req_t("Hello"),
|
||||
print_req_t(" world\n")) )
|
||||
else:
|
||||
ProcessUiActions("JumpQ;JumpName")
|
||||
ProcessUiActions("JumpQ;Breakpoints")
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
import ida_dbg
|
||||
import ida_idaapi
|
||||
import ida_idd
|
||||
import ida_kernwin
|
||||
import ida_typeinf
|
||||
import ida_name
|
||||
|
||||
def log(msg):
|
||||
print(">>> %s" % msg)
|
||||
|
||||
class appcall_hooks_t(ida_dbg.DBG_Hooks):
|
||||
def __init__(self, name_funcs=[]):
|
||||
ida_dbg.DBG_Hooks.__init__(self) # important
|
||||
|
||||
for ea, func_name in name_funcs:
|
||||
log("Renaming 0x%08x to \"%s\"" % (ea, func_name))
|
||||
ida_name.set_name(ea, func_name)
|
||||
|
||||
for func_name, func_proto in [
|
||||
("ref4", "int ref4(int *);"),
|
||||
("ref8", "int ref8(long long int *);"),
|
||||
]:
|
||||
log("Setting '%s's prototype" % func_name)
|
||||
func_ea = ida_name.get_name_ea(ida_idaapi.BADADDR, func_name)
|
||||
assert(ida_typeinf.apply_cdecl(None, func_ea, func_proto))
|
||||
|
||||
|
||||
def dbg_run_to(self, pid, tid, ea):
|
||||
log("'run_to' reached its target location. Performing appcalls.")
|
||||
|
||||
for func_name in ["ref4", "ref8"]:
|
||||
int_value = ida_idd.Appcall.int64(5)
|
||||
int_ptr = ida_idd.Appcall.byref(int_value)
|
||||
if ida_idd.Appcall[func_name](int_ptr):
|
||||
log("Appcall (%s) succeeded: int_value.value=%s, int_ptr.value=%s" % (
|
||||
func_name,
|
||||
int_value.value,
|
||||
int_ptr.value))
|
||||
else:
|
||||
log("Appcall (%s) failed" % func_name)
|
||||
|
||||
|
||||
def run(self):
|
||||
log("Running program up to current address, and letting the hooks do the rest")
|
||||
assert(ida_dbg.run_to(ida_kernwin.get_screen_ea()))
|
||||
@@ -0,0 +1,32 @@
|
||||
"""
|
||||
summary: executing code into the application being debugged (on Linux)
|
||||
|
||||
description:
|
||||
Using the `ida_idd.Appcall` utility to execute code in
|
||||
the process being debugged.
|
||||
|
||||
This example will run the test program and stop wherever
|
||||
the cursor currently is, and then perform an appcall to
|
||||
execute the `ref4` and `ref8` functions.
|
||||
|
||||
To use this example:
|
||||
|
||||
* run `ida64` on test program `simple_appcall_linux64`, or
|
||||
`ida` on test program `simple_appcall_linux32`, and wait for
|
||||
auto-analysis to finish
|
||||
* select the 'linux debugger' (either local, or remote)
|
||||
* run this script
|
||||
|
||||
Note: the real body of code is in `simple_appcall_common.py`.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.append(os.path.dirname(__file__))
|
||||
|
||||
import simple_appcall_common
|
||||
appcall_hooks = simple_appcall_common.appcall_hooks_t()
|
||||
appcall_hooks.hook()
|
||||
appcall_hooks.run()
|
||||
@@ -0,0 +1,48 @@
|
||||
"""
|
||||
summary: executing code into the application being debugged (on Windows)
|
||||
|
||||
description:
|
||||
Using the `ida_idd.Appcall` utility to execute code in
|
||||
the process being debugged.
|
||||
|
||||
This example will run the test program and stop wherever
|
||||
the cursor currently is, and then perform an appcall to
|
||||
execute the `ref4` and `ref8` functions.
|
||||
|
||||
To use this example:
|
||||
|
||||
* run `ida64` on test program `simple_appcall_win64.exe`, or
|
||||
`ida` on test program `simple_appcall_win32.exe`, and wait for
|
||||
auto-analysis to finish
|
||||
* select the 'windows debugger' (either local, or remote)
|
||||
* run this script
|
||||
|
||||
Note: the real body of code is in `simple_appcall_common.py`.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.append(os.path.dirname(__file__))
|
||||
|
||||
# Windows binaries don't have any symbols, thus we'll have
|
||||
# to assign names to addresses of interest before we can
|
||||
# appcall them by name.
|
||||
import ida_ida
|
||||
if ida_ida.inf_is_64bit():
|
||||
ref4_ea = 0x140001000
|
||||
ref8_ea = 0x140001060
|
||||
else:
|
||||
ref4_ea = 0x401000
|
||||
ref8_ea = 0x401050
|
||||
|
||||
import simple_appcall_common
|
||||
appcall_hooks = simple_appcall_common.appcall_hooks_t(
|
||||
name_funcs=[
|
||||
(ref4_ea, "ref4"),
|
||||
(ref8_ea, "ref8"),
|
||||
])
|
||||
|
||||
appcall_hooks.hook()
|
||||
appcall_hooks.run()
|
||||
@@ -0,0 +1,47 @@
|
||||
|
||||
ifdef __NT__
|
||||
EA32_TARGET:=simple_appcall_win32.exe
|
||||
EA64_TARGET:=simple_appcall_win64.exe
|
||||
else
|
||||
ifdef __LINUX__
|
||||
EA32_TARGET:=simple_appcall_linux32
|
||||
EA64_TARGET:=simple_appcall_linux64
|
||||
else
|
||||
$(error Not implemented for OSX)
|
||||
endif
|
||||
endif
|
||||
|
||||
all: $(EA32_TARGET) $(EA64_TARGET)
|
||||
|
||||
simple_appcall_win32.exe: simple_appcall_win32.obj
|
||||
C:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/bin/HostX86/x86/link.exe \
|
||||
/LIBPATH:C:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/lib/x86 \
|
||||
/LIBPATH:C:/PROGRA~2/WI3CF2~1/10/Lib/100171~1.0/ucrt/x86 \
|
||||
/LIBPATH:C:/idasrc/THIRD_~1/mssdk/8.1/Lib/x86 \
|
||||
/OUT:$@ $<
|
||||
|
||||
simple_appcall_win32.obj: simple_appcall.c
|
||||
C:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/bin/HostX86/x86/cl.exe \
|
||||
/IC:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/Include \
|
||||
/IC:/PROGRA~2/WI3CF2~1/10/Include/100171~1.0/ucrt \
|
||||
/Zi /D__NT__ /DNDEBUG /DWIN32 /D_CONSOLE /D__VC__ /c /MD $< /Fo$@
|
||||
|
||||
simple_appcall_win64.exe: simple_appcall_win64.obj
|
||||
C:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/bin/HostX86/x86/link.exe \
|
||||
/LIBPATH:C:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/lib/x64 \
|
||||
/LIBPATH:C:/PROGRA~2/WI3CF2~1/10/Lib/100171~1.0/ucrt/x64 \
|
||||
/LIBPATH:C:/idasrc/THIRD_~1/mssdk/8.1/Lib/x64 \
|
||||
/OUT:$@ $<
|
||||
|
||||
simple_appcall_win64.obj: simple_appcall.c
|
||||
C:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/bin/HostX64/x64/cl.exe \
|
||||
/IC:/PROGRA~2/MIB055~1/2017/PROFES~1/VC/Tools/MSVC/1415~1.267/Include \
|
||||
/IC:/PROGRA~2/WI3CF2~1/10/Include/100171~1.0/ucrt \
|
||||
/Zi /D__NT__ /DNDEBUG /DWIN32 /D_CONSOLE /D__VC__ /c /MD $< /Fo$@
|
||||
|
||||
|
||||
simple_appcall_linux32: simple_appcall.c
|
||||
gcc -m32 -o $@ $<
|
||||
|
||||
simple_appcall_linux64: simple_appcall.c
|
||||
gcc -m64 -o $@ $<
|
||||
@@ -0,0 +1,35 @@
|
||||
#include <stdio.h>
|
||||
|
||||
typedef int int32;
|
||||
int ref4(int32 *a)
|
||||
{
|
||||
if (a == NULL)
|
||||
{
|
||||
printf("ref4: no number passed!");
|
||||
return -1;
|
||||
}
|
||||
printf("ref4: entered with %d\n", *a);
|
||||
(*a)++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef long long int int64;
|
||||
int ref8(int64 *a)
|
||||
{
|
||||
if (a == NULL)
|
||||
{
|
||||
printf("ref8: no number passed!");
|
||||
return -1;
|
||||
}
|
||||
printf("ref8: entered with %lld\n", *a);
|
||||
(*a)++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int32 x;
|
||||
int res = ref4(&x);
|
||||
int64 y;
|
||||
return res + ref8(&y);
|
||||
}
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -1,42 +1,48 @@
|
||||
from __future__ import print_function
|
||||
#---------------------------------------------------------------------
|
||||
# Debug notification hook test
|
||||
#
|
||||
# This script start the executable and steps through the first five
|
||||
# instructions. Each instruction is disassembled after execution.
|
||||
#
|
||||
# Original Author: Gergely Erdelyi <gergely.erdelyi@d-dome.net>
|
||||
#
|
||||
# Maintained By: IDAPython Team
|
||||
#
|
||||
#---------------------------------------------------------------------
|
||||
from idaapi import *
|
||||
"""
|
||||
summary: programmatically drive a debugging session
|
||||
|
||||
class MyDbgHook(DBG_Hooks):
|
||||
description:
|
||||
Start a debugging session, step through the first five
|
||||
instructions. Each instruction is disassembled after
|
||||
execution.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import ida_dbg
|
||||
import ida_ida
|
||||
import ida_lines
|
||||
|
||||
class MyDbgHook(ida_dbg.DBG_Hooks):
|
||||
""" Own debug hook class that implementd the callback functions """
|
||||
|
||||
def __init__(self):
|
||||
ida_dbg.DBG_Hooks.__init__(self) # important
|
||||
self.steps = 0
|
||||
|
||||
def log(self, msg):
|
||||
print(">>> %s" % msg)
|
||||
|
||||
def dbg_process_start(self, pid, tid, ea, name, base, size):
|
||||
print("Process started, pid=%d tid=%d name=%s" % (pid, tid, name))
|
||||
self.log("Process started, pid=%d tid=%d name=%s" % (pid, tid, name))
|
||||
|
||||
def dbg_process_exit(self, pid, tid, ea, code):
|
||||
print("Process exited pid=%d tid=%d ea=0x%x code=%d" % (pid, tid, ea, code))
|
||||
self.log("Process exited pid=%d tid=%d ea=0x%x code=%d" % (pid, tid, ea, code))
|
||||
|
||||
def dbg_library_unload(self, pid, tid, ea, info):
|
||||
print("Library unloaded: pid=%d tid=%d ea=0x%x info=%s" % (pid, tid, ea, info))
|
||||
return 0
|
||||
self.log("Library unloaded: pid=%d tid=%d ea=0x%x info=%s" % (pid, tid, ea, info))
|
||||
|
||||
def dbg_process_attach(self, pid, tid, ea, name, base, size):
|
||||
print("Process attach pid=%d tid=%d ea=0x%x name=%s base=%x size=%x" % (pid, tid, ea, name, base, size))
|
||||
self.log("Process attach pid=%d tid=%d ea=0x%x name=%s base=%x size=%x" % (pid, tid, ea, name, base, size))
|
||||
|
||||
def dbg_process_detach(self, pid, tid, ea):
|
||||
print("Process detached, pid=%d tid=%d ea=0x%x" % (pid, tid, ea))
|
||||
return 0
|
||||
self.log("Process detached, pid=%d tid=%d ea=0x%x" % (pid, tid, ea))
|
||||
|
||||
def dbg_library_load(self, pid, tid, ea, name, base, size):
|
||||
print("Library loaded: pid=%d tid=%d name=%s base=%x" % (pid, tid, name, base))
|
||||
self.log("Library loaded: pid=%d tid=%d name=%s base=%x" % (pid, tid, name, base))
|
||||
|
||||
def dbg_bpt(self, tid, ea):
|
||||
print("Break point at 0x%x pid=%d" % (ea, tid))
|
||||
self.log("Break point at 0x%x pid=%d" % (ea, tid))
|
||||
# return values:
|
||||
# -1 - to display a breakpoint warning dialog
|
||||
# if the process is suspended.
|
||||
@@ -45,11 +51,11 @@ class MyDbgHook(DBG_Hooks):
|
||||
return 0
|
||||
|
||||
def dbg_suspend_process(self):
|
||||
print("Process suspended")
|
||||
self.log("Process suspended")
|
||||
|
||||
def dbg_exception(self, pid, tid, ea, exc_code, exc_can_cont, exc_ea, exc_info):
|
||||
print("Exception: pid=%d tid=%d ea=0x%x exc_code=0x%x can_continue=%d exc_ea=0x%x exc_info=%s" % (
|
||||
pid, tid, ea, exc_code & idaapi.BADADDR, exc_can_cont, exc_ea, exc_info))
|
||||
self.log("Exception: pid=%d tid=%d ea=0x%x exc_code=0x%x can_continue=%d exc_ea=0x%x exc_info=%s" % (
|
||||
pid, tid, ea, exc_code & ida_idaapi.BADADDR, exc_can_cont, exc_ea, exc_info))
|
||||
# return values:
|
||||
# -1 - to display an exception warning dialog
|
||||
# if the process is suspended.
|
||||
@@ -58,30 +64,32 @@ class MyDbgHook(DBG_Hooks):
|
||||
return 0
|
||||
|
||||
def dbg_trace(self, tid, ea):
|
||||
print("Trace tid=%d ea=0x%x" % (tid, ea))
|
||||
self.log("Trace tid=%d ea=0x%x" % (tid, ea))
|
||||
# return values:
|
||||
# 1 - do not log this trace event;
|
||||
# 0 - log it
|
||||
return 0
|
||||
|
||||
def dbg_step_into(self):
|
||||
print("Step into")
|
||||
self.log("Step into")
|
||||
self.dbg_step_over()
|
||||
|
||||
def dbg_run_to(self, pid, tid=0, ea=0):
|
||||
print("Runto: tid=%d" % tid)
|
||||
idaapi.continue_process()
|
||||
|
||||
self.log("Runto: tid=%d, ea=%x" % (tid, ea))
|
||||
ida_dbg.request_step_over()
|
||||
|
||||
def dbg_step_over(self):
|
||||
eip = get_reg_value("EIP")
|
||||
print("0x%x %s" % (eip, GetDisasm(eip)))
|
||||
eip = ida_dbg.get_reg_val("EIP")
|
||||
disasm = ida_lines.tag_remove(
|
||||
ida_lines.generate_disasm_line(
|
||||
eip))
|
||||
self.log("Step over: EIP=0x%x, disassembly=%s" % (eip, disasm))
|
||||
|
||||
self.steps += 1
|
||||
if self.steps >= 5:
|
||||
request_exit_process()
|
||||
ida_dbg.request_exit_process()
|
||||
else:
|
||||
request_step_over()
|
||||
ida_dbg.request_step_over()
|
||||
|
||||
|
||||
# Remove an existing debug hook
|
||||
@@ -95,14 +103,9 @@ except:
|
||||
# Install the debug hook
|
||||
debughook = MyDbgHook()
|
||||
debughook.hook()
|
||||
debughook.steps = 0
|
||||
|
||||
# Stop at the entry point
|
||||
ep = get_inf_attr(INF_START_IP)
|
||||
request_run_to(ep)
|
||||
|
||||
# Step one instruction
|
||||
request_step_over()
|
||||
|
||||
# Start debugging
|
||||
run_requests()
|
||||
ep = ida_ida.inf_get_start_ip()
|
||||
if ida_dbg.request_run_to(ep): # Request stop at entry point
|
||||
ida_dbg.run_requests() # Launch process
|
||||
else:
|
||||
print("Impossible to prepare debugger requests. Is a debugger selected?")
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
"""
|
||||
summary: using the low-level tracing hook
|
||||
|
||||
description:
|
||||
This script demonstrates using the low-level tracing hook
|
||||
(ida_dbg.DBG_Hooks.dbg_trace). It can be run like so:
|
||||
|
||||
ida[t].exe -B -Sdbg_trace.py -Ltrace.log file.exe
|
||||
"""
|
||||
|
||||
import time
|
||||
|
||||
import ida_dbg
|
||||
import ida_ida
|
||||
import ida_pro
|
||||
import ida_ua
|
||||
from ida_allins import NN_callni, NN_call, NN_callfi
|
||||
from ida_lines import generate_disasm_line, GENDSM_FORCE_CODE, GENDSM_REMOVE_TAGS
|
||||
|
||||
# Note: this try/except block below is just there to
|
||||
# let us (at Hex-Rays) test this script in various
|
||||
# situations.
|
||||
try:
|
||||
import idc
|
||||
print(idc.ARGV[1])
|
||||
under_test = bool(idc.ARGV[1])
|
||||
except:
|
||||
under_test = False
|
||||
|
||||
class TraceHook(ida_dbg.DBG_Hooks):
|
||||
def __init__(self):
|
||||
ida_dbg.DBG_Hooks.__init__(self)
|
||||
self.traces = 0
|
||||
self.epReached = False
|
||||
|
||||
def _log(self, msg):
|
||||
print(">>> %s" % msg)
|
||||
|
||||
def dbg_trace(self, tid, ea):
|
||||
# Log all traced addresses
|
||||
if ea < ida_ida.inf_get_min_ea() or ea > ida_ida.inf_get_max_ea():
|
||||
raise Exception(
|
||||
"Received a trace callback for an address outside this database!"
|
||||
)
|
||||
|
||||
self._log("trace %08X" % ea)
|
||||
self.traces += 1
|
||||
insn = ida_ua.insn_t()
|
||||
insnlen = ida_ua.decode_insn(insn, ea)
|
||||
# log disassembly and ESP for call instructions
|
||||
if insnlen > 0 and insn.itype in [NN_callni, NN_call, NN_callfi]:
|
||||
self._log(
|
||||
"call insn: %s"
|
||||
% generate_disasm_line(ea, GENDSM_FORCE_CODE | GENDSM_REMOVE_TAGS)
|
||||
)
|
||||
self._log("ESP=%08X" % ida_dbg.get_reg_val("ESP"))
|
||||
|
||||
return 1
|
||||
|
||||
def dbg_run_to(self, pid, tid=0, ea=0):
|
||||
# this hook is called once execution reaches temporary breakpoint set by run_to(ep) below
|
||||
if not self.epReached:
|
||||
ida_dbg.refresh_debugger_memory()
|
||||
self._log("reached entry point at 0x%X" % ida_dbg.get_reg_val("EIP"))
|
||||
self._log("current step trace options: %x" % ida_dbg.get_step_trace_options())
|
||||
self.epReached = True
|
||||
|
||||
# enable step tracing (single-step the program and generate dbg_trace events)
|
||||
ida_dbg.request_enable_step_trace(1)
|
||||
# change options to only "over debugger segments" (i.e. library functions will be traced)
|
||||
ida_dbg.request_set_step_trace_options(ida_dbg.ST_OVER_DEBUG_SEG)
|
||||
ida_dbg.request_continue_process()
|
||||
ida_dbg.run_requests()
|
||||
|
||||
def dbg_process_exit(self, pid, tid, ea, code):
|
||||
self._log("process exited with %d" % code)
|
||||
self._log("traced %d instructions" % self.traces)
|
||||
return 0
|
||||
|
||||
|
||||
def do_trace(then_quit_ida=True):
|
||||
debugHook = TraceHook()
|
||||
debugHook.hook()
|
||||
|
||||
# Start tracing when entry point is hit
|
||||
ep = ida_ida.inf_get_start_ip()
|
||||
ida_dbg.enable_step_trace(1)
|
||||
ida_dbg.set_step_trace_options(ida_dbg.ST_OVER_DEBUG_SEG | ida_dbg.ST_OVER_LIB_FUNC)
|
||||
print("Running to %x" % ep)
|
||||
ida_dbg.run_to(ep)
|
||||
|
||||
while ida_dbg.get_process_state() != 0:
|
||||
ida_dbg.wait_for_next_event(1, 0)
|
||||
|
||||
if not debugHook.epReached:
|
||||
raise Exception("Entry point wasn't reached!")
|
||||
|
||||
if not debugHook.unhook():
|
||||
raise Exception("Error uninstalling hooks!")
|
||||
|
||||
del debugHook
|
||||
|
||||
if then_quit_ida:
|
||||
# we're done; exit IDA
|
||||
ida_pro.qexit(0)
|
||||
|
||||
|
||||
# load the debugger module depending on the file type
|
||||
if ida_ida.inf_get_filetype() == ida_ida.f_PE:
|
||||
ida_dbg.load_debugger("win32", 0)
|
||||
elif ida_ida.inf_get_filetype() == ida_ida.f_ELF:
|
||||
ida_dbg.load_debugger("linux", 0)
|
||||
elif ida_ida.inf_get_filetype() == ida_ida.f_MACHO:
|
||||
ida_dbg.load_debugger("mac", 0)
|
||||
if not under_test:
|
||||
do_trace()
|
||||
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
summary: print call stack (on Linux)
|
||||
|
||||
description: print the return addresses from the call stack at a breakpoint.
|
||||
(and print also the module and the debug name from debugger)
|
||||
|
||||
To use this example:
|
||||
|
||||
* run `ida64` on test program `simple_appcall_linux64`, or
|
||||
`ida` on test program `simple_appcall_linux32`, and wait for
|
||||
auto-analysis to finish
|
||||
* put a breakpoint where you want to see the call stack
|
||||
* select the 'linux debugger' (either local, or remote)
|
||||
* start debugging
|
||||
* Press Shift+C at the breakpoint
|
||||
"""
|
||||
import os
|
||||
import ida_idaapi
|
||||
import ida_idd
|
||||
import ida_dbg
|
||||
import ida_kernwin
|
||||
import ida_name
|
||||
|
||||
def log(msg):
|
||||
print(">>> %s" % msg)
|
||||
|
||||
class print_call_stack_ah_t():
|
||||
def activate(self, ctx):
|
||||
log("=== start of call stack impression ===")
|
||||
tid = ida_dbg.get_current_thread()
|
||||
trace = ida_idd.call_stack_t()
|
||||
if ida_dbg.collect_stack_trace(tid, trace):
|
||||
for frame in trace:
|
||||
mi = ida_idd.modinfo_t()
|
||||
if ida_dbg.get_module_info(frame.callea, mi):
|
||||
module = os.path.basename(mi.name)
|
||||
name = ida_name.get_nice_colored_name(
|
||||
frame.callea,
|
||||
ida_name.GNCN_NOCOLOR|ida_name.GNCN_NOLABEL|ida_name.GNCN_NOSEG|ida_name.GNCN_PREFDBG)
|
||||
log("Return address: " + hex(frame.callea) + " from: " + module + " with debug name: " + name)
|
||||
else:
|
||||
log("Return address: " + hex(frame.callea))
|
||||
log("=== end of call stack impression ===")
|
||||
|
||||
def update(self, ctx):
|
||||
return ida_kernwin.AST_ENABLE_ALWAYS
|
||||
|
||||
ACTION_NAME = "example:print_call_stack"
|
||||
ACTION_LABEL = "Print call stack"
|
||||
ACTION_SHORTCUT = "Shift+C"
|
||||
ACTION_HELP = "Press %s to dump the call stack" % ACTION_SHORTCUT
|
||||
|
||||
if ida_kernwin.register_action(ida_kernwin.action_desc_t(
|
||||
ACTION_NAME,
|
||||
ACTION_LABEL,
|
||||
print_call_stack_ah_t(),
|
||||
ACTION_SHORTCUT)):
|
||||
print("Registered action \"%s\". %s" % (ACTION_LABEL, ACTION_HELP))
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
"""
|
||||
summary: print all registers, for all threads
|
||||
|
||||
description: iterate over the list of threads in the program being
|
||||
debugged, and dump all registers contents
|
||||
|
||||
To use this example:
|
||||
|
||||
* run `ida64` on test program `simple_appcall_linux64`, or
|
||||
`ida` on test program `simple_appcall_linux32`, and wait for
|
||||
auto-analysis to finish
|
||||
* put a breakpoint somewhere in the code
|
||||
* select the 'linux debugger' (either local, or remote)
|
||||
* start debugging
|
||||
* Press Alt+Shift+C at the breakpoint
|
||||
"""
|
||||
import ida_idd
|
||||
import ida_dbg
|
||||
|
||||
def log(msg):
|
||||
print(">>> %s" % msg)
|
||||
|
||||
class print_registers_ah_t():
|
||||
def activate(self, ctx):
|
||||
log("=== registers ===")
|
||||
dbg = ida_idd.get_dbg()
|
||||
for tidx in range(ida_dbg.get_thread_qty()):
|
||||
tid = ida_dbg.getn_thread(tidx)
|
||||
log(" Thread #%d" % tid)
|
||||
regvals = ida_dbg.get_reg_vals(tid)
|
||||
for ridx, rv in enumerate(regvals):
|
||||
rinfo = dbg.regs(ridx)
|
||||
rval = rv.pyval(rinfo.dtype)
|
||||
if isinstance(rval, int):
|
||||
rval = "0x%x" % rval
|
||||
log(" %s: %s" % (rinfo.name, rval))
|
||||
log("=== end of registers ===")
|
||||
|
||||
def update(self, ctx):
|
||||
return ida_kernwin.AST_ENABLE_ALWAYS
|
||||
|
||||
ACTION_NAME = "example:print_registers"
|
||||
ACTION_LABEL = "Print registers"
|
||||
ACTION_SHORTCUT = "Alt+Shift+C"
|
||||
ACTION_HELP = "Press %s to print the registers" % ACTION_SHORTCUT
|
||||
|
||||
if ida_kernwin.register_action(ida_kernwin.action_desc_t(
|
||||
ACTION_NAME,
|
||||
ACTION_LABEL,
|
||||
print_registers_ah_t(),
|
||||
ACTION_SHORTCUT)):
|
||||
print("Registered action \"%s\". %s" % (ACTION_LABEL, ACTION_HELP))
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
"""
|
||||
summary: adding actions to the "registers" widget(s)
|
||||
|
||||
description:
|
||||
It's possible to add actions to the context menu of
|
||||
pretty much all widgets in IDA.
|
||||
|
||||
This example shows how to do just that for
|
||||
registers-displaying widgets (e.g., "General registers")
|
||||
"""
|
||||
|
||||
import ida_dbg
|
||||
import ida_idd
|
||||
import ida_kernwin
|
||||
import ida_ua
|
||||
|
||||
ACTION_NAME = "registers_context_menu:dump_reg"
|
||||
|
||||
class dump_reg_ah_t(ida_kernwin.action_handler_t):
|
||||
def activate(self, ctx):
|
||||
name = ctx.regname
|
||||
value = ida_dbg.get_reg_val(name)
|
||||
rtype = "integer"
|
||||
rinfo = ida_idd.register_info_t()
|
||||
if ida_dbg.get_dbg_reg_info(name, rinfo):
|
||||
if rinfo.dtype == ida_ua.dt_byte:
|
||||
value = "0x%02x" % value
|
||||
elif rinfo.dtype == ida_ua.dt_word:
|
||||
value = "0x%04x" % value
|
||||
elif rinfo.dtype == ida_ua.dt_dword:
|
||||
value = "0x%08x" % value
|
||||
elif rinfo.dtype == ida_ua.dt_qword:
|
||||
value = "0x%016x" % value
|
||||
else:
|
||||
rtype = "float"
|
||||
print("> Register %s (of type %s): %s" % (name, rtype, value))
|
||||
|
||||
def update(self, ctx):
|
||||
return ida_kernwin.AST_ENABLE_FOR_WIDGET \
|
||||
if ctx.widget_type == ida_kernwin.BWN_CPUREGS \
|
||||
else ida_kernwin.AST_DISABLE_FOR_WIDGET
|
||||
|
||||
|
||||
if ida_kernwin.register_action(
|
||||
ida_kernwin.action_desc_t(
|
||||
ACTION_NAME,
|
||||
"Dump register info",
|
||||
dump_reg_ah_t())):
|
||||
|
||||
class registers_hooks_t(ida_kernwin.UI_Hooks):
|
||||
def finish_populating_widget_popup(self, form, popup):
|
||||
if ida_kernwin.get_widget_type(form) == ida_kernwin.BWN_CPUREGS:
|
||||
ida_kernwin.attach_action_to_popup(form, popup, ACTION_NAME)
|
||||
|
||||
hooks = registers_hooks_t()
|
||||
hooks.hook()
|
||||
else:
|
||||
print("Failed to register action")
|
||||
@@ -1,35 +0,0 @@
|
||||
from __future__ import print_function
|
||||
from tempo import *;
|
||||
|
||||
def test_getmeminfo():
|
||||
L = tempo.getmeminfo()
|
||||
out = []
|
||||
|
||||
# start_ea end_ea name sclass sbase bitness perm
|
||||
for (start_ea, end_ea, name, sclass, sbase, bitness, perm) in L:
|
||||
out.append("%x: %x name=<%s> sclass=<%s> sbase=%x bitness=%2x perm=%2x" % (start_ea, end_ea, name, sclass, sbase, bitness, perm))
|
||||
|
||||
f = file(r"d:\temp\out.log", "w")
|
||||
f.write(("\n".join(out)).encode("UTF-8"))
|
||||
f.close()
|
||||
|
||||
print("dumped meminfo!")
|
||||
|
||||
|
||||
def test_getregs():
|
||||
# name flags class dtype bit_strings bit_strings_default_mask
|
||||
L = tempo.getregs()
|
||||
out = []
|
||||
for (name, flags, cls, dtype, bit_strings, bit_strings_default_mask) in L:
|
||||
out.append("name=<%s> flags=%x class=%x dtype=%x bit_strings_mask=%x" % (name, flags, cls, dtype, bit_strings_default_mask))
|
||||
if bit_strings:
|
||||
for s in bit_strings:
|
||||
out.append(" %s" % s)
|
||||
|
||||
f = file(r"d:\temp\out.log", "w")
|
||||
f.write(("\n".join(out)).encode("UTF-8"))
|
||||
f.close()
|
||||
|
||||
print("dumped regs!")
|
||||
|
||||
|
||||
@@ -1,15 +1,28 @@
|
||||
"""
|
||||
summary: retrieving & dumping debuggee symbols
|
||||
|
||||
description:
|
||||
Queries the debugger (possibly remotely) for the list of
|
||||
symbols that the process being debugged, provides.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import idaapi
|
||||
|
||||
import ida_dbg
|
||||
import ida_ida
|
||||
import ida_name
|
||||
|
||||
def main():
|
||||
if not idaapi.is_debugger_on():
|
||||
if not ida_dbg.is_debugger_on():
|
||||
print("Please run the process first!")
|
||||
return
|
||||
if idaapi.get_process_state() != -1:
|
||||
if ida_dbg.get_process_state() != -1:
|
||||
print("Please suspend the debugger first!")
|
||||
return
|
||||
|
||||
dn = idaapi.get_debug_names(idaapi.cvar.inf.min_ea, idaapi.cvar.inf.max_ea)
|
||||
dn = ida_name.get_debug_names(
|
||||
ida_ida.inf_get_min_ea(),
|
||||
ida_ida.inf_get_max_ea())
|
||||
for i in dn:
|
||||
print("%08x: %s" % (i, dn[i]))
|
||||
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
"""
|
||||
summary: interactively color certain pseudocode lines
|
||||
|
||||
description:
|
||||
Provides an action that can be used to dynamically alter the
|
||||
lines background rendering for pseudocode listings (as opposed to
|
||||
using `ida_hexrays.cfunc_t.pseudocode[N].bgcolor`)
|
||||
|
||||
After running this script, pressing 'M' on a line in a
|
||||
"Pseudocode-?" widget, will cause that line to be rendered
|
||||
with a special background color.
|
||||
|
||||
keywords: colors
|
||||
"""
|
||||
|
||||
import ida_kernwin
|
||||
import ida_hexrays
|
||||
import ida_moves
|
||||
import ida_idaapi
|
||||
|
||||
class pseudo_line_t(object):
|
||||
def __init__(self, func_ea, line_nr):
|
||||
self.func_ea = func_ea
|
||||
self.line_nr = line_nr
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.func_ea, self.line_nr))
|
||||
|
||||
def __eq__(self, r):
|
||||
return self.func_ea == r.func_ea \
|
||||
and self.line_nr == r.line_nr
|
||||
|
||||
|
||||
def _place_to_line_number(p):
|
||||
return ida_kernwin.place_t.as_simpleline_place_t(p).n
|
||||
|
||||
|
||||
class pseudocode_lines_rendering_hooks_t(ida_kernwin.UI_Hooks):
|
||||
def __init__(self):
|
||||
ida_kernwin.UI_Hooks.__init__(self)
|
||||
self.marked_lines = {}
|
||||
|
||||
def get_lines_rendering_info(self, out, widget, rin):
|
||||
vu = ida_hexrays.get_widget_vdui(widget)
|
||||
if vu:
|
||||
entry_ea = vu.cfunc.entry_ea
|
||||
for section_lines in rin.sections_lines:
|
||||
for line in section_lines:
|
||||
coord = pseudo_line_t(
|
||||
entry_ea,
|
||||
_place_to_line_number(line.at))
|
||||
color = self.marked_lines.get(coord, None)
|
||||
if color is not None:
|
||||
e = ida_kernwin.line_rendering_output_entry_t(line)
|
||||
e.bg_color = color
|
||||
out.entries.push_back(e)
|
||||
|
||||
|
||||
class toggle_line_marked_ah_t(ida_kernwin.action_handler_t):
|
||||
|
||||
"""
|
||||
We could very well use an ARGB value, but instead let's go
|
||||
go with a color 'key': those can be altered by the user/theme,
|
||||
and therefore have a better chance of being appropriate (or at
|
||||
least expected.)
|
||||
"""
|
||||
COLOR_KEY = ida_kernwin.CK_EXTRA11
|
||||
|
||||
def __init__(self, hooks):
|
||||
ida_kernwin.action_handler_t.__init__(self)
|
||||
self.hooks = hooks
|
||||
|
||||
def activate(self, ctx):
|
||||
vu = ida_hexrays.get_widget_vdui(ctx.widget)
|
||||
if vu:
|
||||
loc = ida_moves.lochist_entry_t()
|
||||
if ida_kernwin.get_custom_viewer_location(loc, ctx.widget):
|
||||
coord = pseudo_line_t(
|
||||
vu.cfunc.entry_ea,
|
||||
_place_to_line_number(loc.place()))
|
||||
if coord in self.hooks.marked_lines.keys():
|
||||
del self.hooks.marked_lines[coord]
|
||||
else:
|
||||
self.hooks.marked_lines[coord] = self.COLOR_KEY
|
||||
ida_kernwin.refresh_custom_viewer(ctx.widget)
|
||||
|
||||
def update(self, ctx):
|
||||
return ida_kernwin.AST_ENABLE_FOR_WIDGET \
|
||||
if ctx.widget_type == ida_kernwin.BWN_PSEUDOCODE \
|
||||
else ida_kernwin.AST_DISABLE_FOR_WIDGET
|
||||
|
||||
|
||||
hooks = pseudocode_lines_rendering_hooks_t()
|
||||
act_name = "example:colorize_pseudocode_line"
|
||||
act_shortcut = "M"
|
||||
if ida_kernwin.register_action(ida_kernwin.action_desc_t(
|
||||
act_name,
|
||||
"Mark pseudocode line",
|
||||
toggle_line_marked_ah_t(hooks),
|
||||
act_shortcut)):
|
||||
hooks.hook()
|
||||
print("Action registered. Please press '%s' in a pseudocode window to mark a line" % act_shortcut)
|
||||
@@ -0,0 +1,90 @@
|
||||
"""
|
||||
summary: a focus on the 'curpos' hook, printing additional details about user input
|
||||
|
||||
description:
|
||||
Shows how user input information can be retrieved during
|
||||
processing of a notification triggered by that input
|
||||
|
||||
see_also: vds_hooks
|
||||
"""
|
||||
|
||||
import ida_hexrays
|
||||
import ida_kernwin
|
||||
|
||||
class curpos_details_t(ida_hexrays.Hexrays_Hooks):
|
||||
def curpos(self, v):
|
||||
parts = ["cpos={lnnum=%d, x=%d, y=%d}" % (v.cpos.lnnum, v.cpos.x, v.cpos.y)]
|
||||
uie = ida_kernwin.input_event_t()
|
||||
if ida_kernwin.get_user_input_event(uie):
|
||||
kind_str = {
|
||||
ida_kernwin.iek_shortcut : "shortcut",
|
||||
ida_kernwin.iek_key_press : "key_press",
|
||||
ida_kernwin.iek_key_release : "key_release",
|
||||
ida_kernwin.iek_mouse_button_press : "mouse_button_press",
|
||||
ida_kernwin.iek_mouse_button_release : "mouse_button_release",
|
||||
ida_kernwin.iek_mouse_wheel : "mouse_wheel",
|
||||
}[uie.kind]
|
||||
|
||||
#
|
||||
# Retrieve input kind-specific information
|
||||
#
|
||||
if uie.kind == ida_kernwin.iek_shortcut:
|
||||
payload_str = "shortcut={action_name=%s}" % uie.shortcut.action_name
|
||||
elif uie.kind in [
|
||||
ida_kernwin.iek_key_press,
|
||||
ida_kernwin.iek_key_release]:
|
||||
payload_str = "keyboard={key=%d, text=%s}" % (uie.keyboard.key, uie.keyboard.text)
|
||||
else:
|
||||
payload_str = "mouse={x=%d, y=%d, button=%d}" % (
|
||||
uie.mouse.x,
|
||||
uie.mouse.y,
|
||||
uie.mouse.button)
|
||||
|
||||
#
|
||||
# And while at it, retrieve a few extra bits from the
|
||||
# source QEvent as well, why not
|
||||
#
|
||||
qevent = uie.get_source_QEvent()
|
||||
qevent_str = str(qevent)
|
||||
from PyQt5 import QtCore
|
||||
if qevent.type() in [
|
||||
QtCore.QEvent.KeyPress,
|
||||
QtCore.QEvent.KeyRelease]:
|
||||
qevent_str="{count=%d}" % qevent.count()
|
||||
elif qevent.type() in [
|
||||
QtCore.QEvent.MouseButtonPress,
|
||||
QtCore.QEvent.MouseButtonRelease]:
|
||||
qevent_str="{globalX=%d, globalY=%d, flags=%s}" % (
|
||||
qevent.globalX(),
|
||||
qevent.globalY(),
|
||||
qevent.flags())
|
||||
elif qevent.type() == QtCore.QEvent.Wheel:
|
||||
qevent_str="{angleDelta={x=%s, y=%s}, phase=%s}" % (
|
||||
qevent.angleDelta().x(),
|
||||
qevent.angleDelta().y(),
|
||||
qevent.phase())
|
||||
|
||||
#
|
||||
# If the target QWidget is a scroll area's viewport,
|
||||
# pick up the parent
|
||||
#
|
||||
from PyQt5 import QtWidgets
|
||||
qwidget = uie.get_target_QWidget()
|
||||
if qwidget:
|
||||
parent = qwidget.parentWidget()
|
||||
if parent and isinstance(parent, QtWidgets.QAbstractScrollArea):
|
||||
qwidget = parent
|
||||
|
||||
parts.append("user_input_event={kind=%s, modifiers=0x%x, target={metaObject={className=%s}, windowTitle=%s}, source=%s, %s, source-as-qevent=%s}" % (
|
||||
kind_str,
|
||||
uie.modifiers,
|
||||
qwidget.metaObject().className(),
|
||||
qwidget.windowTitle(),
|
||||
uie.source,
|
||||
payload_str,
|
||||
qevent_str))
|
||||
print("### curpos: %s" % ", ".join(parts))
|
||||
return 0
|
||||
|
||||
curpos_details = curpos_details_t()
|
||||
curpos_details.hook()
|
||||
@@ -1,11 +1,16 @@
|
||||
"""
|
||||
summary: automatic decompilation of functions
|
||||
|
||||
description:
|
||||
Attempts to load a decompiler plugin corresponding to the current
|
||||
architecture (and address size) right after auto-analysis is performed,
|
||||
and then tries to decompile the function at the first entrypoint.
|
||||
|
||||
It is particularly suited for use with the '-S' flag, for example:
|
||||
idat -Ldecompile.log -Sdecompile_entry_points.py -c file
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
#
|
||||
# This example tries to load a decompiler plugin corresponding to the current
|
||||
# architecture (and address size) right after auto-analysis is performed,
|
||||
# and then tries to decompile the function at the first entrypoint.
|
||||
#
|
||||
# It is particularly suited for use with the '-S' flag.
|
||||
#
|
||||
|
||||
import ida_ida
|
||||
import ida_auto
|
||||
@@ -13,29 +18,62 @@ import ida_loader
|
||||
import ida_hexrays
|
||||
import ida_idp
|
||||
import ida_entry
|
||||
import ida_kernwin
|
||||
|
||||
ida_auto.auto_wait()
|
||||
ALL_DECOMPILERS = {
|
||||
ida_idp.PLFM_386 : ("hexrays", "hexx64"),
|
||||
ida_idp.PLFM_ARM : ("hexarm", "hexarm64"),
|
||||
ida_idp.PLFM_PPC : ("hexppc", "hexppc64"),
|
||||
}
|
||||
pair = ALL_DECOMPILERS.get(ida_idp.ph.id, None)
|
||||
if pair:
|
||||
decompiler = pair[1 if ida_ida.cvar.inf.is_64bit() else 0]
|
||||
# because the -S script runs very early, we need to load the decompiler
|
||||
# manually if we want to use it
|
||||
def init_hexrays():
|
||||
ALL_DECOMPILERS = {
|
||||
ida_idp.PLFM_386: "hexrays",
|
||||
ida_idp.PLFM_ARM: "hexarm",
|
||||
ida_idp.PLFM_PPC: "hexppc",
|
||||
ida_idp.PLFM_MIPS: "hexmips",
|
||||
}
|
||||
cpu = ida_idp.ph.id
|
||||
decompiler = ALL_DECOMPILERS.get(cpu, None)
|
||||
if not decompiler:
|
||||
print("No known decompilers for architecture with ID: %d" % ida_idp.ph.id)
|
||||
return False
|
||||
if ida_ida.inf_is_64bit():
|
||||
if cpu == ida_idp.PLFM_386:
|
||||
decompiler = "hexx64"
|
||||
else:
|
||||
decompiler += "64"
|
||||
if ida_loader.load_plugin(decompiler) and ida_hexrays.init_hexrays_plugin():
|
||||
return True
|
||||
else:
|
||||
print('Couldn\'t load or initialize decompiler: "%s"' % decompiler)
|
||||
return False
|
||||
|
||||
|
||||
def decompile_func(ea, outfile):
|
||||
ida_kernwin.msg("Decompiling at: %X..." % ea)
|
||||
cf = ida_hexrays.decompile(ea)
|
||||
if cf:
|
||||
ida_kernwin.msg("OK\n")
|
||||
outfile.write(str(cf) + "\n")
|
||||
else:
|
||||
ida_kernwin.msg("failed!\n")
|
||||
outfile.write("decompilation failure at %X!\n" % ea)
|
||||
|
||||
|
||||
def main():
|
||||
print("Waiting for autoanalysis...")
|
||||
ida_auto.auto_wait()
|
||||
if init_hexrays():
|
||||
eqty = ida_entry.get_entry_qty()
|
||||
if eqty:
|
||||
ea = ida_entry.get_entry(ida_entry.get_entry_ordinal(0))
|
||||
print("Decompiling at: %X" % ea)
|
||||
cf = ida_hexrays.decompile(ea)
|
||||
if cf:
|
||||
print(cf)
|
||||
else:
|
||||
print("Decompilation failed")
|
||||
idbpath = idc.get_idb_path()
|
||||
cpath = idbpath[:-4] + ".c"
|
||||
with open(cpath, "w") as outfile:
|
||||
print("writing results to '%s'..." % cpath)
|
||||
for i in range(eqty):
|
||||
ea = ida_entry.get_entry(ida_entry.get_entry_ordinal(i))
|
||||
decompile_func(ea, outfile)
|
||||
else:
|
||||
print("No known entrypoint. Cannot decompile.")
|
||||
else:
|
||||
print("Couldn't load or initialize decompiler: \"%s\"" % decompiler)
|
||||
else:
|
||||
print("No known decompilers for architecture with ID: %d" % ida_idp.ph.id)
|
||||
if ida_kernwin.cvar.batch:
|
||||
print("All done, exiting.")
|
||||
ida_pro.qexit(0)
|
||||
|
||||
main()
|
||||
|
||||
@@ -1,25 +1,33 @@
|
||||
"""
|
||||
summary: decompile & print current function.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import idaapi
|
||||
|
||||
import ida_hexrays
|
||||
import ida_lines
|
||||
import ida_funcs
|
||||
import ida_kernwin
|
||||
|
||||
def main():
|
||||
if not idaapi.init_hexrays_plugin():
|
||||
if not ida_hexrays.init_hexrays_plugin():
|
||||
return False
|
||||
|
||||
print("Hex-rays version %s has been detected" % idaapi.get_hexrays_version())
|
||||
print("Hex-rays version %s has been detected" % ida_hexrays.get_hexrays_version())
|
||||
|
||||
f = idaapi.get_func(idaapi.get_screen_ea());
|
||||
f = ida_funcs.get_func(ida_kernwin.get_screen_ea());
|
||||
if f is None:
|
||||
print("Please position the cursor within a function")
|
||||
return True
|
||||
|
||||
cfunc = idaapi.decompile(f);
|
||||
cfunc = ida_hexrays.decompile(f);
|
||||
if cfunc is None:
|
||||
print("Failed to decompile!")
|
||||
return True
|
||||
|
||||
sv = cfunc.get_pseudocode();
|
||||
for sline in sv:
|
||||
print(idaapi.tag_remove(sline.line));
|
||||
print(ida_lines.tag_remove(sline.line));
|
||||
|
||||
return True
|
||||
|
||||
|
||||
+39
-21
@@ -1,27 +1,28 @@
|
||||
#
|
||||
# Hex-Rays Decompiler project
|
||||
# Copyright (c) 2007-2019 by Hex-Rays, support@hex-rays.com
|
||||
# ALL RIGHTS RESERVED.
|
||||
#
|
||||
# Sample plugin for Hex-Rays Decompiler.
|
||||
# It installs a custom microcode optimization rule:
|
||||
# call !DbgRaiseAssertionFailure <fast:>.0
|
||||
# =>
|
||||
# call !DbgRaiseAssertionFailure <fast:"char *" "assertion text">.0
|
||||
#
|
||||
# To see this plugin in action please use arm64_brk.i64, in the hexrays sdk
|
||||
#
|
||||
# This is a rewrite in Python of the vds10 example that comes with hexrays sdk.
|
||||
#
|
||||
"""
|
||||
summary: a custom microcode instruction optimization rule
|
||||
|
||||
description:
|
||||
Installs a custom microcode instruction optimization rule,
|
||||
to transform:
|
||||
|
||||
call !DbgRaiseAssertionFailure <fast:>.0
|
||||
|
||||
into
|
||||
|
||||
call !DbgRaiseAssertionFailure <fast:"char *" "assertion text">.0
|
||||
|
||||
To see this plugin in action please use arm64_brk.i64
|
||||
"""
|
||||
|
||||
import ida_bytes
|
||||
import ida_range
|
||||
import ida_kernwin
|
||||
import ida_hexrays
|
||||
import ida_typeinf
|
||||
import ida_idaapi
|
||||
|
||||
class nt_assert_optimizer_t(ida_hexrays.optinsn_t):
|
||||
def func(self, blk, ins):
|
||||
def func(self, blk, ins, optflags):
|
||||
if self.handle_nt_assert(ins):
|
||||
return 1
|
||||
return 0
|
||||
@@ -55,10 +56,27 @@ class nt_assert_optimizer_t(ida_hexrays.optinsn_t):
|
||||
fa.size = fa.type.get_size()
|
||||
return True
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# a plugin interface, boilerplate code
|
||||
class my_plugin_t(ida_idaapi.plugin_t):
|
||||
flags = ida_idaapi.PLUGIN_HIDE
|
||||
wanted_name = "Optimize DbgRaiseAssertionFailure (IDAPython)"
|
||||
wanted_hotkey = ""
|
||||
comment = "Sample plugin10 for Hex-Rays decompiler"
|
||||
help = ""
|
||||
def init(self):
|
||||
if ida_hexrays.init_hexrays_plugin():
|
||||
self.optimizer = nt_assert_optimizer_t()
|
||||
self.optimizer.install()
|
||||
return ida_idaapi.PLUGIN_KEEP # keep us in the memory
|
||||
def term(self):
|
||||
self.optimizer.remove()
|
||||
def run(self, arg):
|
||||
if arg == 1:
|
||||
return self.optimizer.remove()
|
||||
elif arg == 2:
|
||||
return self.optimizer.install()
|
||||
|
||||
if ida_hexrays.init_hexrays_plugin():
|
||||
optimizer = nt_assert_optimizer_t()
|
||||
optimizer.install()
|
||||
else:
|
||||
print('vds10: Hex-rays is not available.')
|
||||
def PLUGIN_ENTRY():
|
||||
return my_plugin_t()
|
||||
|
||||
|
||||
+43
-23
@@ -1,27 +1,29 @@
|
||||
#
|
||||
# Hex-Rays Decompiler project
|
||||
# Copyright (c) 2007-2019 by Hex-Rays, support@hex-rays.com
|
||||
# ALL RIGHTS RESERVED.
|
||||
#
|
||||
# Sample plugin for Hex-Rays Decompiler.
|
||||
# It installs a custom block optimization rule:
|
||||
#
|
||||
# goto L1 => goto L2
|
||||
# ...
|
||||
# L1:
|
||||
# goto L2
|
||||
#
|
||||
# In other words we fix a goto target if it points to a chain of gotos.
|
||||
# This improves the decompiler output in some cases.
|
||||
#
|
||||
# This is a rewrite in Python of the vds11 example that comes with hexrays sdk.
|
||||
#
|
||||
"""
|
||||
summary: a custom microcode block optimization rule (resolve `goto` chains)
|
||||
|
||||
description:
|
||||
Installs a custom microcode block optimization rule,
|
||||
to transform:
|
||||
|
||||
goto L1
|
||||
...
|
||||
L1:
|
||||
goto L2
|
||||
|
||||
into
|
||||
|
||||
goto L2
|
||||
|
||||
In other words we fix a goto target if it points to a chain of gotos.
|
||||
This improves the decompiler output in some cases.
|
||||
"""
|
||||
|
||||
import ida_bytes
|
||||
import ida_range
|
||||
import ida_kernwin
|
||||
import ida_hexrays
|
||||
import ida_typeinf
|
||||
import ida_idaapi
|
||||
|
||||
class goto_optimizer_t(ida_hexrays.optblock_t):
|
||||
def func(self, blk):
|
||||
@@ -71,9 +73,27 @@ class goto_optimizer_t(ida_hexrays.optblock_t):
|
||||
mba.verify(True);
|
||||
return True
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# a plugin interface, boilerplate code
|
||||
class my_plugin_t(ida_idaapi.plugin_t):
|
||||
flags = ida_idaapi.PLUGIN_HIDE
|
||||
wanted_name = "Optimize goto chains (IDAPython)"
|
||||
wanted_hotkey = ""
|
||||
comment = "Sample plugin11 for Hex-Rays decompiler"
|
||||
help = ""
|
||||
def init(self):
|
||||
if ida_hexrays.init_hexrays_plugin():
|
||||
self.optimizer = goto_optimizer_t()
|
||||
self.optimizer.install()
|
||||
return ida_idaapi.PLUGIN_KEEP # keep us in the memory
|
||||
def term(self):
|
||||
self.optimizer.remove()
|
||||
def run(self, arg):
|
||||
if arg == 1:
|
||||
return self.optimizer.remove()
|
||||
elif arg == 2:
|
||||
return self.optimizer.install()
|
||||
|
||||
def PLUGIN_ENTRY():
|
||||
return my_plugin_t()
|
||||
|
||||
if ida_hexrays.init_hexrays_plugin():
|
||||
optimizer = goto_optimizer_t()
|
||||
optimizer.install()
|
||||
else:
|
||||
print('vds11: Hex-rays is not available.')
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
#
|
||||
# Hex-Rays Decompiler project
|
||||
# Copyright (c) 2007-2019 by Hex-Rays, support@hex-rays.com
|
||||
# ALL RIGHTS RESERVED.
|
||||
#
|
||||
# Sample plugin for Hex-Rays Decompiler.
|
||||
# It shows list of direct references to a register from the current
|
||||
# instruction.
|
||||
#
|
||||
# This is a rewrite in Python of the vds12 example that comes with hexrays sdk.
|
||||
#
|
||||
"""
|
||||
summary: list instruction registers
|
||||
|
||||
description:
|
||||
Shows a list of direct references to a register from the
|
||||
current instruction.
|
||||
"""
|
||||
|
||||
import ida_pro
|
||||
import ida_hexrays
|
||||
@@ -107,7 +103,7 @@ if ida_hexrays.init_hexrays_plugin():
|
||||
mbr,
|
||||
hf,
|
||||
None,
|
||||
ida_hexrays.DECOMP_WARNINGS,
|
||||
ida_hexrays.DECOMP_WARNINGS | ida_hexrays.DECOMP_NO_CACHE,
|
||||
ida_hexrays.MMAT_PREOPTIMIZED)
|
||||
if mba:
|
||||
merr = mba.build_graph()
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
#
|
||||
# Hex-Rays Decompiler project
|
||||
# Copyright (c) 2007-2019 by Hex-Rays, support@hex-rays.com
|
||||
# ALL RIGHTS RESERVED.
|
||||
#
|
||||
# Sample plugin for Hex-Rays Decompiler.
|
||||
# It generates microcode for selection and dumps it to the output window.
|
||||
#
|
||||
# This is a rewrite in Python of the vds13 example that comes with hexrays sdk.
|
||||
#
|
||||
"""
|
||||
summary: generates microcode for selection
|
||||
|
||||
description:
|
||||
Generates microcode for selection and dumps it to the output window.
|
||||
"""
|
||||
|
||||
import ida_bytes
|
||||
import ida_range
|
||||
|
||||
+43
-24
@@ -1,20 +1,21 @@
|
||||
#
|
||||
# Hex-Rays Decompiler project
|
||||
# Copyright (c) 2007-2019 by Hex-Rays, support@hex-rays.com
|
||||
# ALL RIGHTS RESERVED.
|
||||
#
|
||||
# Sample plugin for Hex-Rays Decompiler.
|
||||
# It shows how to use "Select offsets" widget (select_udt_by_offset() call).
|
||||
# This plugin repeats the Alt-Y functionality.
|
||||
# Usage: place cursor on the union field and press Shift-T
|
||||
#
|
||||
# This is a rewrite in Python of the vds17 example that comes with hexrays sdk.
|
||||
#
|
||||
"""
|
||||
summary: using the "Select offsets" widget
|
||||
|
||||
description:
|
||||
Registers an action opens the "Select offsets" widget
|
||||
(select_udt_by_offset() call).
|
||||
|
||||
This effectively repeats the functionality already available
|
||||
through Alt+Y.
|
||||
|
||||
Place cursor on the union field and press Shift+T
|
||||
"""
|
||||
|
||||
import ida_idaapi
|
||||
import ida_hexrays
|
||||
import ida_lines
|
||||
import ida_typeinf
|
||||
import ida_kernwin
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
class func_stroff_ah_t(ida_kernwin.action_handler_t):
|
||||
@@ -26,14 +27,16 @@ class func_stroff_ah_t(ida_kernwin.action_handler_t):
|
||||
vu = ida_hexrays.get_widget_vdui(ctx.widget)
|
||||
vu.get_current_item(ida_hexrays.USE_KEYBOARD)
|
||||
|
||||
# REGION1, will be referenced latter
|
||||
# REGION1, will be referenced later
|
||||
# check that the current item is a union field
|
||||
if not vu.item.is_citem():
|
||||
ida_kernwin.warning("Please position the cursor on a union member")
|
||||
return 0
|
||||
e = vu.item.e
|
||||
while True:
|
||||
op = e.op
|
||||
if op != ida_hexrays.cot_memptr and op != ida_hexrays.cot_memref:
|
||||
ida_kernwin.warning("Please position the cursor on a union member")
|
||||
return 0
|
||||
e = e.x
|
||||
if op == ida_hexrays.cot_memptr:
|
||||
@@ -43,6 +46,7 @@ class func_stroff_ah_t(ida_kernwin.action_handler_t):
|
||||
if ida_typeinf.remove_pointer(e.type).is_union():
|
||||
break
|
||||
if not e.type.is_udt():
|
||||
ida_kernwin.warning("Please position the cursor on a union member")
|
||||
return 0
|
||||
# END REGION1
|
||||
|
||||
@@ -98,6 +102,7 @@ class func_stroff_ah_t(ida_kernwin.action_handler_t):
|
||||
# the item itself may be unaddressable.
|
||||
# TODO: find its addressable parent
|
||||
if ea == ida_idaapi.BADADDR:
|
||||
ida_kernwin.warning("Sorry, the current item is not addressable")
|
||||
return 0
|
||||
# END REGION4
|
||||
|
||||
@@ -126,7 +131,7 @@ class func_stroff_ah_t(ida_kernwin.action_handler_t):
|
||||
|
||||
def apply(self, opnum, path, top_tif, spath):
|
||||
typename = ida_typeinf.print_tinfo('', 0, 0, ida_typeinf.PRTYPE_1LINE, top_tif, '', '')
|
||||
idaapi.msg("User selected %s of type %s\n" % (spath, typename))
|
||||
ida_kernwin.msg("User selected %s of type %s\n" % (spath, typename))
|
||||
if path.empty():
|
||||
return False
|
||||
vu.cfunc.set_user_union_selection(self.ea, path)
|
||||
@@ -151,16 +156,30 @@ class func_stroff_ah_t(ida_kernwin.action_handler_t):
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
if ida_hexrays.init_hexrays_plugin():
|
||||
print("Hex-rays version %s has been detected, Structure offsets ready to use" % ida_hexrays.get_hexrays_version())
|
||||
ida_kernwin.register_action(
|
||||
ida_kernwin.action_desc_t(
|
||||
"vds17:strchoose",
|
||||
"Structure offsets",
|
||||
func_stroff_ah_t(),
|
||||
"Shift+T"))
|
||||
else:
|
||||
print('vds17: Hex-rays is not available.')
|
||||
# a plugin interface, boilerplate code
|
||||
class my_plugin_t(ida_idaapi.plugin_t):
|
||||
flags = ida_idaapi.PLUGIN_HIDE
|
||||
wanted_name = "Structure offsets (IDAPython)"
|
||||
wanted_hotkey = ""
|
||||
comment = "Sample plugin17 for Hex-Rays decompiler"
|
||||
help = ""
|
||||
def init(self):
|
||||
if ida_hexrays.init_hexrays_plugin():
|
||||
print("Hex-rays version %s has been detected, Structure offsets ready to use" % ida_hexrays.get_hexrays_version())
|
||||
ida_kernwin.register_action(
|
||||
ida_kernwin.action_desc_t(
|
||||
"vds17:strchoose",
|
||||
"Structure offsets",
|
||||
func_stroff_ah_t(),
|
||||
"Shift+T"))
|
||||
return ida_idaapi.PLUGIN_KEEP # keep us in the memory
|
||||
def term(self):
|
||||
pass
|
||||
def run(self, arg):
|
||||
pass
|
||||
|
||||
def PLUGIN_ENTRY():
|
||||
return my_plugin_t()
|
||||
|
||||
"""
|
||||
# A few notes about the VDS17 sample
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
"""
|
||||
summary: a custom microcode instruction optimization rule (`x | ~x => -1`)
|
||||
|
||||
description:
|
||||
Installs a custom microcode instruction optimization rule,
|
||||
to transform:
|
||||
|
||||
x | ~x
|
||||
|
||||
into
|
||||
|
||||
-1
|
||||
|
||||
To see this plugin in action please use be_ornot_be.idb
|
||||
"""
|
||||
|
||||
import ida_hexrays
|
||||
import ida_idaapi
|
||||
|
||||
# recognize "x | ~x" and replace by -1
|
||||
class subinsn_optimizer_t(ida_hexrays.minsn_visitor_t):
|
||||
cnt = 0
|
||||
def visit_minsn(self): # for each instruction...
|
||||
ins = self.curins # take a reference to the current instruction
|
||||
|
||||
# THE CORE OF THE PLUGIN IS HERE:
|
||||
# check the pattern "x | ~x"
|
||||
if ins.opcode == ida_hexrays.m_or and ins.r.is_insn(ida_hexrays.m_bnot) and ins.l == ins.r.d.l:
|
||||
if not ins.l.has_side_effects(): # avoid destroying side effects
|
||||
# pattern matched, convert to "mov -1, ..."
|
||||
ins.opcode = ida_hexrays.m_mov
|
||||
ins.l.make_number(-1, ins.r.size)
|
||||
ins.r = ida_hexrays.mop_t()
|
||||
self.cnt = self.cnt + 1 # number of changes we made
|
||||
return 0 # continue traversal
|
||||
|
||||
# a custom instruction optimizer, boilerplate code
|
||||
class sample_optimizer_t(ida_hexrays.optinsn_t):
|
||||
def func(self, blk, ins, optflags):
|
||||
opt = subinsn_optimizer_t()
|
||||
ins.for_all_insns(opt)
|
||||
if opt.cnt != 0: # if we modified microcode,
|
||||
blk.mba.verify(True) # run the verifier
|
||||
return opt.cnt # report the number of changes
|
||||
|
||||
# a plugin interface, boilerplate code
|
||||
class my_plugin_t(ida_idaapi.plugin_t):
|
||||
flags = ida_idaapi.PLUGIN_HIDE
|
||||
wanted_name = "optimize x|~x"
|
||||
wanted_hotkey = ""
|
||||
comment = ""
|
||||
help = ""
|
||||
def init(self):
|
||||
if ida_hexrays.init_hexrays_plugin():
|
||||
self.optimizer = sample_optimizer_t()
|
||||
self.optimizer.install()
|
||||
print("Installed sample optimizer for 'x | ~x'")
|
||||
return ida_idaapi.PLUGIN_KEEP # keep us in the memory
|
||||
def term(self):
|
||||
self.optimizer.remove()
|
||||
def run(self, arg):
|
||||
if arg == 1:
|
||||
return self.optimizer.remove()
|
||||
elif arg == 2:
|
||||
return self.optimizer.install()
|
||||
|
||||
def PLUGIN_ENTRY():
|
||||
return my_plugin_t()
|
||||
@@ -0,0 +1,97 @@
|
||||
"""
|
||||
summary: dynamically provide a custom call type
|
||||
|
||||
description:
|
||||
This plugin can greatly improve decompilation of indirect calls:
|
||||
|
||||
call [eax+4]
|
||||
|
||||
For them, the decompiler has to guess the prototype of the called function.
|
||||
This has to be done at a very early phase of decompilation because
|
||||
the function prototype influences the data flow analysis. On the other
|
||||
hand, we do not have global data flow analysis results yet because
|
||||
we haven't analyzed all calls in the function. It is a chicked-and-egg
|
||||
problem.
|
||||
|
||||
The decompiler uses various techniques to guess the called function
|
||||
prototype. While it works very well, it may fail in some cases.
|
||||
|
||||
To fix, the user can specify the call prototype manually, using
|
||||
"Edit, Operand types, Set operand type" at the call instruction.
|
||||
|
||||
This plugin illustrates another approach to the problem:
|
||||
if you happen to be able to calculate the call prototypes dynamically,
|
||||
this is how to inform the decompiler about them.
|
||||
"""
|
||||
|
||||
import ida_idaapi
|
||||
import ida_nalt
|
||||
import ida_kernwin
|
||||
import ida_typeinf
|
||||
import ida_hexrays
|
||||
|
||||
testing = False # only for testing purposes
|
||||
|
||||
class callinfo_provider_t(ida_hexrays.Hexrays_Hooks):
|
||||
|
||||
# this callback will be called for all call instructions
|
||||
# our plugin may provide the function prototype or even a complete new callinfo
|
||||
# object. The callinfo object may be useful if the prototype is not enough
|
||||
# to express all details of the call.
|
||||
def build_callinfo(self, blk, type):
|
||||
# it is a good idea to skip direct calls.
|
||||
# note that some indirect calls may be resolved and become direct calls,
|
||||
# and will be filtered out here:
|
||||
ida_kernwin.msg("%x: got called for: %s\n" % (blk.tail.ea, blk.tail.dstr()))
|
||||
tail = blk.tail
|
||||
if tail.opcode == ida_hexrays.m_call:
|
||||
return
|
||||
|
||||
# also, if the type was specified by the user, do not interfere
|
||||
call_ea = tail.ea
|
||||
tif = ida_typeinf.tinfo_t()
|
||||
if ida_nalt.get_op_tinfo(tif, call_ea, 0):
|
||||
return
|
||||
|
||||
global testing
|
||||
if not testing:
|
||||
# ok, the decompiler really has to guess the type.
|
||||
# just for the sake of an example, return a predefined prototype.
|
||||
# in real life you will provide the prototype you discovered yourself,
|
||||
# using your magic of yours :)
|
||||
my_proto = "int f();"
|
||||
ida_kernwin.msg("%x: providing prototype %s\n" % (call_ea, my_proto))
|
||||
ida_typeinf.parse_decl(type, None, my_proto, 0)
|
||||
else:
|
||||
# as an alternative to filling 'type', you can
|
||||
# choose to return a mcallinfo_t instance.
|
||||
mi = ida_hexrays.mcallinfo_t()
|
||||
mi.cc = ida_typeinf.CM_CC_STDCALL | ida_typeinf.CM_N32_F48 # let's use stdcall to differentiate from the tinfo_t-filling version
|
||||
mi.return_type = ida_typeinf.tinfo_t(ida_typeinf.BT_INT)
|
||||
mi.return_argloc.set_reg1(0) # eax
|
||||
return mi
|
||||
|
||||
# a plugin interface, boilerplate code
|
||||
class my_plugin_t(ida_idaapi.plugin_t):
|
||||
flags = ida_idaapi.PLUGIN_HIDE
|
||||
wanted_name = "Hex-Rays custom prototype provider (IDAPython)"
|
||||
wanted_hotkey = ""
|
||||
comment = "Sample plugin21 for Hex-Rays decompiler"
|
||||
help = ""
|
||||
def init(self):
|
||||
if ida_hexrays.init_hexrays_plugin():
|
||||
self.hooks = callinfo_provider_t()
|
||||
self.hooks.hook()
|
||||
ida_kernwin.warning(
|
||||
"Installed callinfo provider sample (vds21.py)\n" +\
|
||||
"Please note that it is just an example\n" +\
|
||||
"and will spoil your decompilations!")
|
||||
return ida_idaapi.PLUGIN_KEEP # keep us in the memory
|
||||
def term(self):
|
||||
self.hooks.unhook()
|
||||
def run(self, arg):
|
||||
pass
|
||||
|
||||
def PLUGIN_ENTRY():
|
||||
return my_plugin_t()
|
||||
|
||||
+106
-48
@@ -1,14 +1,47 @@
|
||||
""" Invert the then and else blocks of a cif_t.
|
||||
|
||||
Author: EiNSTeiN_ <einstein@g3nius.org>
|
||||
|
||||
This is a rewrite in Python of the vds3 example that comes with hexrays sdk.
|
||||
"""
|
||||
summary: invert if/else blocks
|
||||
|
||||
description:
|
||||
Registers an action that can be used to invert the `if`
|
||||
and `else` blocks of a `ida_hexrays.cif_t`.
|
||||
|
||||
For example, a statement like
|
||||
|
||||
if ( cond )
|
||||
{
|
||||
statements1;
|
||||
}
|
||||
else
|
||||
{
|
||||
statements2;
|
||||
}
|
||||
|
||||
will be displayed as
|
||||
|
||||
if ( !cond )
|
||||
{
|
||||
statements2;
|
||||
}
|
||||
else
|
||||
{
|
||||
statements1;
|
||||
}
|
||||
|
||||
The modifications are persistent: the user can quit & restart
|
||||
IDA, and the changes will be present.
|
||||
|
||||
author: EiNSTeiN_ (einstein@g3nius.org)
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import idautils
|
||||
import idaapi
|
||||
import idc
|
||||
|
||||
import ida_kernwin
|
||||
import ida_hexrays
|
||||
import ida_netnode
|
||||
import ida_idaapi
|
||||
import ida_idp
|
||||
|
||||
import traceback
|
||||
|
||||
@@ -16,20 +49,20 @@ NETNODE_NAME = '$ hexrays-inverted-if'
|
||||
|
||||
inverter_actname = "vds3:invert"
|
||||
|
||||
class invert_action_handler_t(idaapi.action_handler_t):
|
||||
class invert_action_handler_t(ida_kernwin.action_handler_t):
|
||||
def __init__(self, inverter):
|
||||
idaapi.action_handler_t.__init__(self)
|
||||
ida_kernwin.action_handler_t.__init__(self)
|
||||
self.inverter = inverter
|
||||
|
||||
def activate(self, ctx):
|
||||
vdui = idaapi.get_widget_vdui(ctx.widget)
|
||||
vdui = ida_hexrays.get_widget_vdui(ctx.widget)
|
||||
self.inverter.invert_if_event(vdui)
|
||||
return 1
|
||||
|
||||
def update(self, ctx):
|
||||
return idaapi.AST_ENABLE_FOR_WIDGET if \
|
||||
ctx.widget_type == idaapi.BWN_PSEUDOCODE else \
|
||||
idaapi.AST_DISABLE_FOR_WIDGET
|
||||
return ida_kernwin.AST_ENABLE_FOR_WIDGET if \
|
||||
ctx.widget_type == ida_kernwin.BWN_PSEUDOCODE else \
|
||||
ida_kernwin.AST_DISABLE_FOR_WIDGET
|
||||
|
||||
|
||||
class hexrays_callback_info(object):
|
||||
@@ -37,7 +70,7 @@ class hexrays_callback_info(object):
|
||||
def __init__(self):
|
||||
self.vu = None
|
||||
|
||||
self.node = idaapi.netnode()
|
||||
self.node = ida_netnode.netnode()
|
||||
if not self.node.create(NETNODE_NAME):
|
||||
# node exists
|
||||
self.load()
|
||||
@@ -53,7 +86,7 @@ class hexrays_callback_info(object):
|
||||
try:
|
||||
data = self.node.getblob(0, 'I')
|
||||
if data:
|
||||
self.stored = eval(data)
|
||||
self.stored = eval(data.decode("UTF-8"))
|
||||
print('Invert-if: Loaded %s' % (repr(self.stored), ))
|
||||
except:
|
||||
print('Failed to load invert-if locations')
|
||||
@@ -65,7 +98,7 @@ class hexrays_callback_info(object):
|
||||
def save(self):
|
||||
|
||||
try:
|
||||
self.node.setblob(repr(self.stored), 0, 'I')
|
||||
self.node.setblob(repr(self.stored).encode("UTF-8"), 0, 'I')
|
||||
except:
|
||||
print('Failed to save invert-if locations')
|
||||
traceback.print_exc()
|
||||
@@ -73,7 +106,7 @@ class hexrays_callback_info(object):
|
||||
|
||||
return
|
||||
|
||||
def invert_if(self, cfunc, insn):
|
||||
def invert_if(self, insn):
|
||||
|
||||
if insn.opname != 'if':
|
||||
return False
|
||||
@@ -83,12 +116,12 @@ class hexrays_callback_info(object):
|
||||
if not cif.ithen or not cif.ielse:
|
||||
return False
|
||||
|
||||
idaapi.qswap(cif.ithen, cif.ielse)
|
||||
ida_hexrays.qswap(cif.ithen, cif.ielse)
|
||||
# Make a copy of 'cif.expr': 'lnot' might destroy its toplevel
|
||||
# cexpr_t and return a pointer to its direct child (but we'll want to
|
||||
# 'swap' it later, the 'cif.expr' cexpr_t object must remain valid.)
|
||||
cond = idaapi.cexpr_t(cif.expr)
|
||||
notcond = idaapi.lnot(cond)
|
||||
cond = ida_hexrays.cexpr_t(cif.expr)
|
||||
notcond = ida_hexrays.lnot(cond)
|
||||
|
||||
cif.expr.swap(notcond)
|
||||
|
||||
@@ -104,26 +137,26 @@ class hexrays_callback_info(object):
|
||||
|
||||
def find_if_statement(self, vu):
|
||||
|
||||
vu.get_current_item(idaapi.USE_KEYBOARD)
|
||||
vu.get_current_item(ida_hexrays.USE_KEYBOARD)
|
||||
item = vu.item
|
||||
|
||||
if item.is_citem() and item.it.op == idaapi.cit_if and item.it.to_specific_type.cif.ielse is not None:
|
||||
if item.is_citem() and item.it.op == ida_hexrays.cit_if and item.it.to_specific_type.cif.ielse is not None:
|
||||
return item.it.to_specific_type
|
||||
|
||||
if vu.tail.citype == idaapi.VDI_TAIL and vu.tail.loc.itp == idaapi.ITP_ELSE:
|
||||
if vu.tail.citype == ida_hexrays.VDI_TAIL and vu.tail.loc.itp == ida_hexrays.ITP_ELSE:
|
||||
# for tail marks, we know only the corresponding ea,
|
||||
# not the pointer to if-statement
|
||||
# find it by walking the whole ctree
|
||||
class if_finder_t(idaapi.ctree_visitor_t):
|
||||
class if_finder_t(ida_hexrays.ctree_visitor_t):
|
||||
def __init__(self, ea):
|
||||
idaapi.ctree_visitor_t.__init__(self, idaapi.CV_FAST | idaapi.CV_INSNS)
|
||||
ida_hexrays.ctree_visitor_t.__init__(self, ida_hexrays.CV_FAST | ida_hexrays.CV_INSNS)
|
||||
|
||||
self.ea = ea
|
||||
self.found = None
|
||||
return
|
||||
|
||||
def visit_insn(self, i):
|
||||
if i.op == idaapi.cit_if and i.ea == self.ea:
|
||||
if i.op == ida_hexrays.cit_if and i.ea == self.ea:
|
||||
self.found = i
|
||||
return 1 # stop enumeration
|
||||
return 0
|
||||
@@ -136,12 +169,11 @@ class hexrays_callback_info(object):
|
||||
|
||||
def invert_if_event(self, vu):
|
||||
|
||||
cfunc = vu.cfunc.__deref__()
|
||||
i = self.find_if_statement(vu)
|
||||
if not i:
|
||||
return False
|
||||
|
||||
if self.invert_if(cfunc, i):
|
||||
if self.invert_if(i):
|
||||
vu.refresh_ctext()
|
||||
self.add_location(i.ea)
|
||||
|
||||
@@ -149,18 +181,18 @@ class hexrays_callback_info(object):
|
||||
|
||||
def restore(self, cfunc):
|
||||
|
||||
class visitor(idaapi.ctree_visitor_t):
|
||||
class visitor(ida_hexrays.ctree_visitor_t):
|
||||
|
||||
def __init__(self, inverter, cfunc):
|
||||
idaapi.ctree_visitor_t.__init__(self, idaapi.CV_FAST | idaapi.CV_INSNS)
|
||||
ida_hexrays.ctree_visitor_t.__init__(self, ida_hexrays.CV_FAST | ida_hexrays.CV_INSNS)
|
||||
self.inverter = inverter
|
||||
self.cfunc = cfunc
|
||||
return
|
||||
|
||||
def visit_insn(self, i):
|
||||
try:
|
||||
if i.op == idaapi.cit_if and i.ea in self.inverter.stored:
|
||||
self.inverter.invert_if(self.cfunc, i)
|
||||
if i.op == ida_hexrays.cit_if and i.ea in self.inverter.stored:
|
||||
self.inverter.invert_if(i)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
return 0 # continue enumeration
|
||||
@@ -170,31 +202,57 @@ class hexrays_callback_info(object):
|
||||
return
|
||||
|
||||
|
||||
class vds3_hooks_t(idaapi.Hexrays_Hooks):
|
||||
class vds3_hooks_t(ida_hexrays.Hexrays_Hooks):
|
||||
def __init__(self, i):
|
||||
idaapi.Hexrays_Hooks.__init__(self)
|
||||
ida_hexrays.Hexrays_Hooks.__init__(self)
|
||||
self.i = i
|
||||
|
||||
def populating_popup(self, widget, phandle, vu):
|
||||
idaapi.attach_action_to_popup(vu.ct, None, inverter_actname)
|
||||
ida_kernwin.attach_action_to_popup(vu.ct, None, inverter_actname)
|
||||
return 0
|
||||
|
||||
def maturity(self, cfunc, maturity):
|
||||
if maturity == idaapi.CMAT_FINAL:
|
||||
if maturity == ida_hexrays.CMAT_FINAL:
|
||||
self.i.restore(cfunc)
|
||||
return 0
|
||||
|
||||
class idp_hooks_t(ida_idp.IDP_Hooks):
|
||||
def __init__(self, i):
|
||||
ida_idp.IDP_Hooks.__init__(self)
|
||||
self.i = i
|
||||
|
||||
if idaapi.init_hexrays_plugin():
|
||||
i = hexrays_callback_info()
|
||||
idaapi.register_action(
|
||||
idaapi.action_desc_t(
|
||||
inverter_actname,
|
||||
"Invert then/else",
|
||||
invert_action_handler_t(i),
|
||||
"I"))
|
||||
vds3_hooks = vds3_hooks_t(i)
|
||||
vds3_hooks.hook()
|
||||
else:
|
||||
print('invert-if: hexrays is not available.')
|
||||
# 'node' refers to index of the named node, this index became invalid after
|
||||
# privrange moving, so we recreate the node here to update nodeidx
|
||||
def ev_privrange_changed(self, old_privrange, delta):
|
||||
i.node.create(NETNODE_NAME)
|
||||
|
||||
|
||||
# a plugin interface, boilerplate code
|
||||
class my_plugin_t(ida_idaapi.plugin_t):
|
||||
flags = ida_idaapi.PLUGIN_HIDE
|
||||
wanted_name = "Hex-Rays if-inverter (IDAPython)"
|
||||
wanted_hotkey = ""
|
||||
comment = "Sample plugin3 for Hex-Rays decompiler"
|
||||
help = ""
|
||||
def init(self):
|
||||
if ida_hexrays.init_hexrays_plugin():
|
||||
i = hexrays_callback_info()
|
||||
ida_kernwin.register_action(
|
||||
ida_kernwin.action_desc_t(
|
||||
inverter_actname,
|
||||
"Invert then/else",
|
||||
invert_action_handler_t(i),
|
||||
"I"))
|
||||
self.vds3_hooks = vds3_hooks_t(i)
|
||||
self.vds3_hooks.hook()
|
||||
# we need this hook to react to privrange moving event
|
||||
self.idp_hooks = idp_hooks_t(i)
|
||||
self.idp_hooks.hook()
|
||||
return ida_idaapi.PLUGIN_KEEP # keep us in the memory
|
||||
def term(self):
|
||||
self.vds3_hooks.unhook()
|
||||
def run(self, arg):
|
||||
pass
|
||||
|
||||
def PLUGIN_ENTRY():
|
||||
return my_plugin_t()
|
||||
|
||||
+43
-34
@@ -1,58 +1,67 @@
|
||||
""" Print user-defined details to the output window.
|
||||
|
||||
Author: EiNSTeiN_ <einstein@g3nius.org>
|
||||
|
||||
This is a rewrite in Python of the vds4 example that comes with hexrays sdk.
|
||||
"""
|
||||
summary: dump user-defined information
|
||||
|
||||
description:
|
||||
Prints user-defined information to the "Output" window.
|
||||
Namely:
|
||||
|
||||
* user defined label names
|
||||
* user defined indented comments
|
||||
* user defined number formats
|
||||
* user defined local variable names, types, comments
|
||||
|
||||
This script loads information from the database without decompiling anything.
|
||||
|
||||
author: EiNSTeiN_ (einstein@g3nius.org)
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import idautils
|
||||
import idaapi
|
||||
import idc
|
||||
|
||||
import traceback
|
||||
import ida_kernwin
|
||||
import ida_hexrays
|
||||
import ida_bytes
|
||||
|
||||
def run():
|
||||
|
||||
cfunc = idaapi.decompile(idaapi.get_screen_ea())
|
||||
if not cfunc:
|
||||
print('Please move the cursor into a function.')
|
||||
return
|
||||
|
||||
entry_ea = cfunc.entry_ea
|
||||
print("Dump of user-defined information for function at %x" % (entry_ea, ))
|
||||
f = ida_funcs.get_func(ida_kernwin.get_screen_ea());
|
||||
if f is None:
|
||||
print("Please position the cursor within a function")
|
||||
return True
|
||||
entry_ea = f.start_ea
|
||||
print("Dump of user-defined information for function at %x" % entry_ea)
|
||||
|
||||
# Display user defined labels.
|
||||
labels = idaapi.restore_user_labels(entry_ea);
|
||||
labels = ida_hexrays.restore_user_labels(entry_ea);
|
||||
if labels is not None:
|
||||
print("------- %u user defined labels" % (len(labels), ))
|
||||
print("------- %u user defined labels" % len(labels))
|
||||
for org_label, name in labels.items():
|
||||
print("Label %d: %s" % (org_label, str(name)))
|
||||
idaapi.user_labels_free(labels)
|
||||
ida_hexrays.user_labels_free(labels)
|
||||
|
||||
# Display user defined comments
|
||||
cmts = idaapi.restore_user_cmts(entry_ea);
|
||||
cmts = ida_hexrays.restore_user_cmts(entry_ea);
|
||||
if cmts is not None:
|
||||
print("------- %u user defined comments" % (len(cmts), ))
|
||||
for tl, cmt in cmts.items():
|
||||
print("Comment at %x, preciser %x:\n%s\n" % (tl.ea, tl.itp, str(cmt)))
|
||||
idaapi.user_cmts_free(cmts)
|
||||
ida_hexrays.user_cmts_free(cmts)
|
||||
|
||||
# Display user defined citem iflags
|
||||
iflags = idaapi.restore_user_iflags(entry_ea)
|
||||
iflags = ida_hexrays.restore_user_iflags(entry_ea)
|
||||
if iflags is not None:
|
||||
print("------- %u user defined citem iflags" % (len(iflags), ))
|
||||
for cl, f in iflags.items():
|
||||
print("%x(%d): %08X%s" % (cl.ea, cl.op, f, " CIT_COLLAPSED" if f & idaapi.CIT_COLLAPSED else ""))
|
||||
idaapi.user_iflags_free(iflags)
|
||||
print("%x(%d): %08X%s" % (cl.ea, cl.op, f, " CIT_COLLAPSED" if f & ida_hexrays.CIT_COLLAPSED else ""))
|
||||
ida_hexrays.user_iflags_free(iflags)
|
||||
|
||||
# Display user defined number formats
|
||||
numforms = idaapi.restore_user_numforms(entry_ea)
|
||||
numforms = ida_hexrays.restore_user_numforms(entry_ea)
|
||||
if numforms is not None:
|
||||
print("------- %u user defined number formats" % (len(numforms), ))
|
||||
for ol, nf in numforms.items():
|
||||
|
||||
print("Number format at %a, operand %d: %s" % (ol.ea, ol.opnum, "negated " if (nf.props & NF_NEGATE) != 0 else ""))
|
||||
print("Number format at %a, operand %d: %s" % \
|
||||
(ol.ea,
|
||||
ol.opnum,
|
||||
"negated " if (ord(nf.props) & ida_hexrays.NF_NEGATE) != 0 else ""))
|
||||
|
||||
if nf.is_enum():
|
||||
print("enum %s (serial %d)" % (str(nf.type_name), nf.serial))
|
||||
@@ -64,13 +73,13 @@ def run():
|
||||
print("struct offset %s" % (str(nf.type_name), ))
|
||||
|
||||
else:
|
||||
print("number base=%d" % (idaapi.get_radix(nf.flags, ol.opnum), ))
|
||||
print("number base=%d" % (ida_bytes.get_radix(nf.flags, ol.opnum), ))
|
||||
|
||||
idaapi.user_numforms_free(numforms)
|
||||
ida_hexrays.user_numforms_free(numforms)
|
||||
|
||||
# Display user-defined local variable information
|
||||
lvinf = idaapi.lvar_uservec_t()
|
||||
if idaapi.restore_user_lvar_settings(lvinf, entry_ea):
|
||||
lvinf = ida_hexrays.lvar_uservec_t()
|
||||
if ida_hexrays.restore_user_lvar_settings(lvinf, entry_ea):
|
||||
print("------- User defined local variable information\n")
|
||||
for lv in lvinf.lvvec:
|
||||
print("Lvar defined at %x" % (lv.ll.defea, ))
|
||||
@@ -89,7 +98,7 @@ def run():
|
||||
return
|
||||
|
||||
|
||||
if idaapi.init_hexrays_plugin():
|
||||
if ida_hexrays.init_hexrays_plugin():
|
||||
run()
|
||||
else:
|
||||
print('dump user info: hexrays is not available.')
|
||||
|
||||
+40
-13
@@ -1,11 +1,25 @@
|
||||
"""
|
||||
summary: show ctree graph
|
||||
|
||||
description:
|
||||
Registers an action that can be used to show the graph of the ctree.
|
||||
The current item will be highlighted in the graph.
|
||||
|
||||
The command shortcut is `Ctrl+Shift+G`, and is also added
|
||||
to the context menu.
|
||||
|
||||
To display the graph, we produce a .gdl file, and
|
||||
request that ida displays that using `ida_gdl.display_gdl`.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import ida_idaapi
|
||||
import ida_pro
|
||||
import ida_hexrays
|
||||
import ida_kernwin
|
||||
import ida_gdl
|
||||
import ida_lines
|
||||
import ida_idaapi
|
||||
|
||||
ACTION_NAME = "vds5.py:displaygraph"
|
||||
ACTION_SHORTCUT = "Ctrl+Shift+G"
|
||||
@@ -296,18 +310,31 @@ class display_graph_ah_t(ida_kernwin.action_handler_t):
|
||||
|
||||
class vds5_hooks_t(ida_hexrays.Hexrays_Hooks):
|
||||
def populating_popup(self, widget, handle, vu):
|
||||
idaapi.attach_action_to_popup(vu.ct, None, ACTION_NAME)
|
||||
ida_kernwin.attach_action_to_popup(vu.ct, None, ACTION_NAME)
|
||||
return 0
|
||||
|
||||
if ida_hexrays.init_hexrays_plugin():
|
||||
ida_kernwin.register_action(
|
||||
ida_kernwin.action_desc_t(
|
||||
ACTION_NAME,
|
||||
"Hex-Rays show C graph (IDAPython)",
|
||||
display_graph_ah_t(),
|
||||
ACTION_SHORTCUT))
|
||||
vds5_hooks = vds5_hooks_t()
|
||||
vds5_hooks.hook()
|
||||
else:
|
||||
print('hexrays-graph: hexrays is not available.')
|
||||
# a plugin interface, boilerplate code
|
||||
class my_plugin_t(ida_idaapi.plugin_t):
|
||||
flags = ida_idaapi.PLUGIN_HIDE
|
||||
wanted_name = "Hex-Rays show C graph (IDAPython)"
|
||||
wanted_hotkey = ""
|
||||
comment = "Sample plugin5 for Hex-Rays decompiler"
|
||||
help = ""
|
||||
def init(self):
|
||||
if ida_hexrays.init_hexrays_plugin():
|
||||
ida_kernwin.register_action(
|
||||
ida_kernwin.action_desc_t(
|
||||
ACTION_NAME,
|
||||
"Hex-Rays show C graph (IDAPython)",
|
||||
display_graph_ah_t(),
|
||||
ACTION_SHORTCUT))
|
||||
self.vds5_hooks = vds5_hooks_t()
|
||||
self.vds5_hooks.hook()
|
||||
return ida_idaapi.PLUGIN_KEEP # keep us in the memory
|
||||
def term(self):
|
||||
self.vds5_hooks.unhook()
|
||||
def run(self, arg):
|
||||
pass
|
||||
|
||||
def PLUGIN_ENTRY():
|
||||
return my_plugin_t()
|
||||
|
||||
+29
-12
@@ -1,10 +1,13 @@
|
||||
|
||||
"""
|
||||
This is a crude (and not very pythonic) reimplementation of the example
|
||||
hexrays plugin 'hexrays_sample6.cpp', shipped with the Hex-Rays decompiler.
|
||||
summary: superficially modify the decompilation output
|
||||
|
||||
It modifies the decompilation output: removes some space characters.
|
||||
description:
|
||||
modifies the decompilation output in a superficial manner,
|
||||
by removing some white spaces
|
||||
|
||||
Note: this is rather crude, not quite "pythonic" code.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import idautils
|
||||
@@ -51,6 +54,9 @@ def remove_spaces(sl):
|
||||
last = None # last seen character
|
||||
while True:
|
||||
# go until comments
|
||||
if l.startswith("//"):
|
||||
push(l)
|
||||
break
|
||||
dbg("-" * 60)
|
||||
nchars = ida_lines.tag_advance(l, 1)
|
||||
push(l[0:nchars])
|
||||
@@ -58,9 +64,6 @@ def remove_spaces(sl):
|
||||
l = my_tag_skipcodes(l, out)
|
||||
if not l:
|
||||
break
|
||||
if l.startswith("//"):
|
||||
push(l)
|
||||
break
|
||||
c = l[0]
|
||||
dbg("c: '%s', last: '%s', l: '%s'" % (c, last, l))
|
||||
if delim:
|
||||
@@ -89,8 +92,22 @@ class vds6_hooks_t(ida_hexrays.Hexrays_Hooks):
|
||||
remove_spaces(sl);
|
||||
return 0
|
||||
|
||||
if ida_hexrays.init_hexrays_plugin():
|
||||
vds6_hooks = vds6_hooks_t()
|
||||
vds6_hooks.hook()
|
||||
else:
|
||||
print('remove spaces: hexrays is not available.')
|
||||
# a plugin interface, boilerplate code
|
||||
class my_plugin_t(ida_idaapi.plugin_t):
|
||||
flags = ida_idaapi.PLUGIN_HIDE
|
||||
wanted_name = "Hex-Rays space remover (IDAPython)"
|
||||
wanted_hotkey = ""
|
||||
comment = "Sample plugin6 for Hex-Rays decompiler"
|
||||
help = ""
|
||||
def init(self):
|
||||
if ida_hexrays.init_hexrays_plugin():
|
||||
self.vds6_hooks = vds6_hooks_t()
|
||||
self.vds6_hooks.hook()
|
||||
return ida_idaapi.PLUGIN_KEEP # keep us in the memory
|
||||
def term(self):
|
||||
self.vds6_hooks.unhook()
|
||||
def run(self, arg):
|
||||
pass
|
||||
|
||||
def PLUGIN_ENTRY():
|
||||
return my_plugin_t()
|
||||
|
||||
+17
-25
@@ -1,31 +1,25 @@
|
||||
""" It demonstrates how to iterate a cblock_t object.
|
||||
|
||||
Author: EiNSTeiN_ <einstein@g3nius.org>
|
||||
|
||||
This is a rewrite in Python of the vds7 example that comes with hexrays sdk.
|
||||
"""
|
||||
summary: iterate a cblock_t object
|
||||
|
||||
description:
|
||||
Using a `ida_hexrays.ctree_visitor_t`, search for
|
||||
`ida_hexrays.cit_block` instances and dump them.
|
||||
|
||||
author: EiNSTeiN_ (einstein@g3nius.org)
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import idautils
|
||||
import idaapi
|
||||
import idc
|
||||
import ida_hexrays
|
||||
|
||||
import traceback
|
||||
|
||||
class cblock_visitor_t(idaapi.ctree_visitor_t):
|
||||
class cblock_visitor_t(ida_hexrays.ctree_visitor_t):
|
||||
|
||||
def __init__(self):
|
||||
idaapi.ctree_visitor_t.__init__(self, idaapi.CV_FAST)
|
||||
return
|
||||
ida_hexrays.ctree_visitor_t.__init__(self, ida_hexrays.CV_FAST)
|
||||
|
||||
def visit_insn(self, ins):
|
||||
|
||||
try:
|
||||
if ins.op == idaapi.cit_block:
|
||||
self.dump_block(ins.ea, ins.cblock)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
if ins.op == ida_hexrays.cit_block:
|
||||
self.dump_block(ins.ea, ins.cblock)
|
||||
return 0
|
||||
|
||||
def dump_block(self, ea, b):
|
||||
@@ -34,18 +28,16 @@ class cblock_visitor_t(idaapi.ctree_visitor_t):
|
||||
for ins in b:
|
||||
print(" %x: insn %s" % (ins.ea, ins.opname))
|
||||
|
||||
return
|
||||
|
||||
|
||||
class vds7_hooks_t(idaapi.Hexrays_Hooks):
|
||||
class vds7_hooks_t(ida_hexrays.Hexrays_Hooks):
|
||||
def maturity(self, cfunc, maturity):
|
||||
if maturity == idaapi.CMAT_BUILT:
|
||||
if maturity == ida_hexrays.CMAT_BUILT:
|
||||
cbv = cblock_visitor_t()
|
||||
cbv.apply_to(cfunc.body, None)
|
||||
return 0
|
||||
|
||||
|
||||
if idaapi.init_hexrays_plugin():
|
||||
if ida_hexrays.init_hexrays_plugin():
|
||||
vds7_hooks = vds7_hooks_t()
|
||||
vds7_hooks.hook()
|
||||
else:
|
||||
|
||||
+12
-10
@@ -1,14 +1,16 @@
|
||||
"""
|
||||
summary: using `ida_hexrays.udc_filter_t`
|
||||
|
||||
# Hex-Rays Decompiler project
|
||||
# Copyright (c) 2007-2019 by Hex-Rays, support@hex-rays.com
|
||||
# ALL RIGHTS RESERVED.
|
||||
#
|
||||
# Sample script for Hex-Rays Decompiler usage of udc_filter_t
|
||||
# class: decompile svc 0x900001 and svc 0x9000F8 as function calls to
|
||||
# svc_exit() and svc_exit_group() respectively.
|
||||
# NOTE: You will need to have an ARM + Linux IDB for this script to be usable
|
||||
#
|
||||
# It is also added into the right-click menu as "vds8.py:Toggle UDC"
|
||||
description:
|
||||
Registers an action that uses a `ida_hexrays.udc_filter_t` to decompile
|
||||
`svc 0x900001` and `svc 0x9000F8` as function calls to
|
||||
`svc_exit()` and `svc_exit_group()` respectively.
|
||||
|
||||
You will need to have an ARM + Linux IDB for this script to be usable
|
||||
|
||||
In addition to having a shortcut, the action will be present
|
||||
in the context menu.
|
||||
"""
|
||||
|
||||
import ida_idaapi
|
||||
import ida_hexrays
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
"""'Hints' example for Hexrays Decompiler
|
||||
"""
|
||||
summary: decompiler hints
|
||||
|
||||
Handle 'hxe_create_hint' notification using hooks, to return our own.
|
||||
If the object under the cursor is:
|
||||
- a function call, prefix the original decompiler hint with "==> "
|
||||
- a local variable declaration, replace the hint with our own in the form of "!{varname}" (where '{varname}' is replaced w/ the variable name)
|
||||
- an 'if' statement, replace the hint with our own, saying "condition"
|
||||
description:
|
||||
Handle `ida_hexrays.hxe_create_hint` notification using hooks,
|
||||
to return our own.
|
||||
|
||||
If the object under the cursor is:
|
||||
|
||||
* a function call, prefix the original decompiler hint with `==> `
|
||||
* a local variable declaration, replace the hint with our own in
|
||||
the form of `!{varname}` (where `{varname}` is replaced with the
|
||||
variable name)
|
||||
* an `if` statement, replace the hint with our own, saying "condition"
|
||||
"""
|
||||
|
||||
import ida_idaapi
|
||||
|
||||
@@ -1,18 +1,33 @@
|
||||
"""
|
||||
Various hooks for Hexrays Decompiler
|
||||
summary: various decompiler hooks
|
||||
|
||||
description:
|
||||
Shows how to hook to many notifications sent by the decompiler.
|
||||
|
||||
This plugin doesn't really accomplish anything: it just prints
|
||||
the parameters.
|
||||
|
||||
The list of notifications handled below should be exhaustive,
|
||||
and is there to hint at what is possible to accomplish by
|
||||
subclassing `ida_hexrays.Hexrays_Hooks`
|
||||
|
||||
see_also: curpos_details
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import inspect
|
||||
|
||||
import ida_idaapi
|
||||
import ida_typeinf
|
||||
import ida_hexrays
|
||||
|
||||
class vds_hooks_t(ida_hexrays.Hexrays_Hooks):
|
||||
def _shorten(self, cfunc):
|
||||
raw = str(cfunc)
|
||||
if len(raw) > 20:
|
||||
raw = raw[0:20] + "[...snipped...]"
|
||||
return raw
|
||||
def __init__(self):
|
||||
ida_hexrays.Hexrays_Hooks.__init__(self)
|
||||
self.display_shortened_cfuncs = False
|
||||
self.display_vdui_curpos = False
|
||||
self.inhibit_log = 0;
|
||||
|
||||
def _format_lvar(self, v):
|
||||
parts = []
|
||||
@@ -26,106 +41,132 @@ class vds_hooks_t(ida_hexrays.Hexrays_Hooks):
|
||||
parts.append("divisor=%s" % v.divisor)
|
||||
return "{%s}" % ", ".join(parts)
|
||||
|
||||
def _log(self, msg):
|
||||
print("### %s" % msg)
|
||||
def _format_vdui_curpos(self, v):
|
||||
return "cpos={lnnum=%d, x=%d, y=%d}" % (v.cpos.lnnum, v.cpos.x, v.cpos.y)
|
||||
|
||||
def _format_value(self, v):
|
||||
if isinstance(v, ida_hexrays.lvar_t):
|
||||
v = self._format_lvar(v)
|
||||
elif isinstance(v, ida_hexrays.cfunc_t):
|
||||
if self.display_shortened_cfuncs:
|
||||
self.inhibit_log += 1
|
||||
v = str(v)
|
||||
if len(v) > 20:
|
||||
v = v[0:20] + "[...snipped...]"
|
||||
self.inhibit_log -= 1
|
||||
else:
|
||||
v = "<cfunc>" # cannot print contents: we'll end up being called recursively
|
||||
elif isinstance(v, ida_hexrays.vdui_t) and self.display_vdui_curpos:
|
||||
v = str(v) + " " + self._format_vdui_curpos(v)
|
||||
return str(v)
|
||||
|
||||
def _log(self):
|
||||
if self.inhibit_log <= 0:
|
||||
stack = inspect.stack()
|
||||
frame, _, _, _, _, _ = stack[1]
|
||||
args, _, _, values = inspect.getargvalues(frame)
|
||||
method_name = inspect.getframeinfo(frame)[2]
|
||||
argstrs = []
|
||||
for arg in args[1:]:
|
||||
argstrs.append("%s=%s" % (arg, self._format_value(values[arg])))
|
||||
print("### %s: %s" % (method_name, ", ".join(argstrs)))
|
||||
return 0
|
||||
|
||||
def flowchart(self, fc):
|
||||
return self._log("flowchart: fc=%s" % fc)
|
||||
return self._log()
|
||||
|
||||
def stkpnts(self, mba, stkpnts):
|
||||
return self._log("stkpnts: mba=%s, stkpnts=%s" % (mba, stkpnts))
|
||||
return self._log()
|
||||
|
||||
def prolog(self, mba, fc, reachable_blocks, decomp_flags):
|
||||
return self._log("prolog: mba=%s, fc=%s, reachable_blocks=%s, decomp_flags=%x" % (mba, fc, reachable_blocks, decomp_flags))
|
||||
return self._log()
|
||||
|
||||
def microcode(self, mba):
|
||||
return self._log("microcode: mba=%s" % (mba,))
|
||||
return self._log()
|
||||
|
||||
def preoptimized(self, mba):
|
||||
return self._log("preoptimized: mba=%s" % (mba,))
|
||||
return self._log()
|
||||
|
||||
def locopt(self, mba):
|
||||
return self._log("locopt: mba=%s" % (mba,))
|
||||
return self._log()
|
||||
|
||||
def prealloc(self, mba):
|
||||
return self._log("prealloc: mba=%s" % (mba,))
|
||||
return self._log()
|
||||
|
||||
def glbopt(self, mba):
|
||||
return self._log("glbopt: mba=%s" % (mba,))
|
||||
return self._log()
|
||||
|
||||
def structural(self, ctrl_graph):
|
||||
return self._log("structural: ctrl_graph: %s" % (ctrl_graph,))
|
||||
return self._log()
|
||||
|
||||
def maturity(self, cfunc, maturity):
|
||||
return self._log("maturity: cfunc=%s, maturity=%s" % (self._shorten(cfunc), maturity))
|
||||
return self._log()
|
||||
|
||||
def interr(self, code):
|
||||
return self._log("interr: code=%s" % (code,))
|
||||
return self._log()
|
||||
|
||||
def combine(self, blk, insn):
|
||||
return self._log("combine: blk=%s, insn=%s" % (blk, insn))
|
||||
return self._log()
|
||||
|
||||
def print_func(self, cfunc, printer):
|
||||
# Note: we can't print/str()-ify 'cfunc' here,
|
||||
# because that'll call print_func() us recursively.
|
||||
return self._log("print_func: cfunc=..., printer=%s" % (printer,))
|
||||
return self._log()
|
||||
|
||||
def func_printed(self, cfunc):
|
||||
return self._log("func_printed: cfunc=%s" % (cfunc,))
|
||||
return self._log()
|
||||
|
||||
def resolve_stkaddrs(self, mba):
|
||||
return self._log("resolve_stkaddrs: mba=%s" % (mba,))
|
||||
return self._log()
|
||||
|
||||
def open_pseudocode(self, vu):
|
||||
return self._log("open_pseudocode: vu=%s" % (vu,))
|
||||
return self._log()
|
||||
|
||||
def switch_pseudocode(self, vu):
|
||||
return self._log("switch_pseudocode: vu=%s" % (vu,))
|
||||
return self._log()
|
||||
|
||||
def refresh_pseudocode(self, vu):
|
||||
return self._log("refresh_pseudocode: vu=%s" % (vu,))
|
||||
return self._log()
|
||||
|
||||
def close_pseudocode(self, vu):
|
||||
return self._log("close_pseudocode: vu=%s" % (vu,))
|
||||
return self._log()
|
||||
|
||||
def keyboard(self, vu, key_code, shift_state):
|
||||
return self._log("keyboard: vu=%s, key_code=%s, shift_state=%s" % (vu, key_code, shift_state))
|
||||
return self._log()
|
||||
|
||||
def right_click(self, vu):
|
||||
return self._log("right_click: vu=%s" % (vu,))
|
||||
return self._log()
|
||||
|
||||
def double_click(self, vu, shift_state):
|
||||
return self._log("double_click: vu=%s, shift_state=%s" % (vu, shift_state))
|
||||
return self._log()
|
||||
|
||||
def curpos(self, vu):
|
||||
return self._log("curpos: vu=%s (vu.cpos.lnnum=%d, vu.cpos.x=%d, vu.cpos.y=%d)" % (
|
||||
vu, vu.cpos.lnnum, vu.cpos.x, vu.cpos.y))
|
||||
return self._log()
|
||||
|
||||
def create_hint(self, vu):
|
||||
return self._log("create_hint: vu=%s: " % (vu,))
|
||||
return self._log()
|
||||
|
||||
def text_ready(self, vu):
|
||||
return self._log("text_ready: vu=%s" % (vu,))
|
||||
return self._log()
|
||||
|
||||
def populating_popup(self, widget, popup, vu):
|
||||
return self._log("populating_popup: widget=%s, popup=%s, vu=%s" % (widget, popup, vu))
|
||||
return self._log()
|
||||
|
||||
def lvar_name_changed(self, vu, v, name, is_user_name):
|
||||
return self._log("lvar_name_changed: vu=%s, v=%s, name=%s, is_user_name=%s" % (vu, self._format_lvar(v), name, is_user_name))
|
||||
return self._log()
|
||||
|
||||
def lvar_type_changed(self, vu, v, tif):
|
||||
return self._log("lvar_type_changed: vu=%s, v=%s, tinfo=%s" % (vu, self._format_lvar(v), tif._print()))
|
||||
return self._log()
|
||||
|
||||
def lvar_cmt_changed(self, vu, v, cmt):
|
||||
return self._log("lvar_cmt_changed: vu=%s, v=%s, cmt=%s" % (vu, self._format_lvar(v), cmt))
|
||||
return self._log()
|
||||
|
||||
def lvar_mapping_changed(self, vu, _from, to):
|
||||
return self._log("lvar_mapping_changed: vu=%s, from=%s, to=%s" % (vu, _from, to))
|
||||
return self._log()
|
||||
|
||||
def cmt_changed(self, cfunc, loc, cmt):
|
||||
return self._log("cmt_changed: cfunc=%s, loc=%s, cmt=%s" % (self._shorten(cfunc),loc, cmt))
|
||||
return self._log()
|
||||
|
||||
def build_callinfo(self, *args):
|
||||
return self._log()
|
||||
|
||||
vds_hooks = vds_hooks_t()
|
||||
vds_hooks.hook()
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
"""
|
||||
summary: modifying local variables
|
||||
|
||||
description:
|
||||
Use a `ida_hexrays.user_lvar_modifier_t` to modify names,
|
||||
comments and/or types of local variables.
|
||||
"""
|
||||
|
||||
import ida_hexrays
|
||||
import ida_typeinf
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
""" Xref script for Hexrays Decompiler
|
||||
"""
|
||||
summary: show decompiler xrefs
|
||||
|
||||
Author: EiNSTeiN_ <einstein@g3nius.org>
|
||||
description:
|
||||
Show decompiler-style Xref when the `Ctrl+X` key is
|
||||
pressed in the Decompiler window.
|
||||
|
||||
Show decompiler-style Xref when the X key is pressed in the Decompiler window.
|
||||
|
||||
- It supports any global name: functions, strings, integers, etc.
|
||||
- It supports structure member.
|
||||
* supports any global name: functions, strings, integers, ...
|
||||
* supports structure member.
|
||||
|
||||
author: EiNSTeiN_ (einstein@g3nius.org)
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import ida_kernwin
|
||||
import ida_hexrays
|
||||
import ida_typeinf
|
||||
import ida_idaapi
|
||||
import ida_struct
|
||||
import ida_funcs
|
||||
|
||||
import idautils
|
||||
import idaapi
|
||||
import idc
|
||||
|
||||
import traceback
|
||||
|
||||
@@ -21,27 +28,27 @@ from PyQt5 import QtCore, QtWidgets
|
||||
XREF_EA = 0
|
||||
XREF_STRUC_MEMBER = 1
|
||||
|
||||
class XrefsForm(idaapi.PluginForm):
|
||||
class XrefsForm(ida_kernwin.PluginForm):
|
||||
|
||||
def __init__(self, target):
|
||||
|
||||
idaapi.PluginForm.__init__(self)
|
||||
ida_kernwin.PluginForm.__init__(self)
|
||||
|
||||
self.target = target
|
||||
|
||||
if type(self.target) == idaapi.cfunc_t:
|
||||
if type(self.target) == ida_hexrays.cfunc_t:
|
||||
|
||||
self.__type = XREF_EA
|
||||
self.__ea = self.target.entry_ea
|
||||
self.__name = 'Xrefs of %x' % (self.__ea, )
|
||||
|
||||
elif type(self.target) == idaapi.cexpr_t and self.target.opname == 'obj':
|
||||
elif type(self.target) == ida_hexrays.cexpr_t and self.target.opname == 'obj':
|
||||
|
||||
self.__type = XREF_EA
|
||||
self.__ea = self.target.obj_ea
|
||||
self.__name = 'Xrefs of %x' % (self.__ea, )
|
||||
|
||||
elif type(self.target) == idaapi.cexpr_t and self.target.opname in ('memptr', 'memref'):
|
||||
elif type(self.target) == ida_hexrays.cexpr_t and self.target.opname in ('memptr', 'memref'):
|
||||
|
||||
self.__type = XREF_STRUC_MEMBER
|
||||
name = self.get_struc_name()
|
||||
@@ -59,10 +66,11 @@ class XrefsForm(idaapi.PluginForm):
|
||||
|
||||
xtype = x.type
|
||||
xtype.remove_ptr_or_array()
|
||||
typename = idaapi.print_tinfo('', 0, 0, idaapi.PRTYPE_1LINE, xtype, '', '')
|
||||
typename = ida_typeinf.print_tinfo('', 0, 0, ida_typeinf.PRTYPE_1LINE, xtype, '', '')
|
||||
|
||||
sid = idc.get_struc_id(typename)
|
||||
member = idc.get_member_name(sid, m)
|
||||
sid = ida_struct.get_struc_id(typename)
|
||||
sptr = ida_struct.get_struc(sid)
|
||||
member = ida_struct.get_member(sptr, m)
|
||||
|
||||
return '%s::%s' % (typename, member)
|
||||
|
||||
@@ -76,7 +84,7 @@ class XrefsForm(idaapi.PluginForm):
|
||||
return
|
||||
|
||||
def Show(self):
|
||||
idaapi.PluginForm.Show(self, self.__name)
|
||||
ida_kernwin.PluginForm.Show(self, self.__name)
|
||||
return
|
||||
|
||||
def populate_form(self):
|
||||
@@ -109,7 +117,7 @@ class XrefsForm(idaapi.PluginForm):
|
||||
def double_clicked(self, row, column):
|
||||
|
||||
ea = self.functions[row]
|
||||
idaapi.open_pseudocode(ea, True)
|
||||
ida_hexrays.open_pseudocode(ea, True)
|
||||
|
||||
return
|
||||
|
||||
@@ -125,12 +133,12 @@ class XrefsForm(idaapi.PluginForm):
|
||||
lines = []
|
||||
for stmt in insnvec:
|
||||
|
||||
qp = idaapi.qstring_printer_t(cfunc.__deref__(), False)
|
||||
qp = ida_hexrays.qstring_printer_t(cfunc, False)
|
||||
|
||||
stmt._print(0, qp)
|
||||
s = qp.s.split('\n')[0]
|
||||
|
||||
#~ s = idaapi.tag_remove(s)
|
||||
#~ s = ida_lines.tag_remove(s)
|
||||
lines.append(s)
|
||||
|
||||
return '\n'.join(lines)
|
||||
@@ -141,18 +149,13 @@ class XrefsForm(idaapi.PluginForm):
|
||||
|
||||
items = []
|
||||
for ea in frm:
|
||||
try:
|
||||
cfunc = idaapi.decompile(ea)
|
||||
|
||||
self.functions.append(cfunc.entry_ea)
|
||||
self.items.append((ea, idc.get_func_name(cfunc.entry_ea), self.get_decompiled_line(cfunc, ea)))
|
||||
|
||||
except Exception as e:
|
||||
print('could not decompile: %s' % (str(e), ))
|
||||
raise
|
||||
|
||||
return
|
||||
cfunc = ida_hexrays.decompile(ea)
|
||||
if not cfunc:
|
||||
print('Decompilation of %x failed' % (ea, ))
|
||||
continue
|
||||
|
||||
self.functions.append(cfunc.entry_ea)
|
||||
self.items.append((ea, ida_funcs.get_func_name(cfunc.entry_ea) or "", self.get_decompiled_line(cfunc, ea)))
|
||||
def get_items_for_type(self):
|
||||
|
||||
x = self.target.operands['x']
|
||||
@@ -160,36 +163,35 @@ class XrefsForm(idaapi.PluginForm):
|
||||
|
||||
xtype = x.type
|
||||
xtype.remove_ptr_or_array()
|
||||
typename = idaapi.print_tinfo('', 0, 0, idaapi.PRTYPE_1LINE, xtype, '', '')
|
||||
typename = ida_typeinf.print_tinfo('', 0, 0, ida_typeinf.PRTYPE_1LINE, xtype, '', '')
|
||||
|
||||
addresses = []
|
||||
for ea in idautils.Functions():
|
||||
|
||||
try:
|
||||
cfunc = idaapi.decompile(ea)
|
||||
except:
|
||||
cfunc = ida_hexrays.decompile(ea)
|
||||
if not cfunc:
|
||||
print('Decompilation of %x failed' % (ea, ))
|
||||
continue
|
||||
|
||||
str(cfunc)
|
||||
print(str(cfunc)) # KLUDGE
|
||||
|
||||
for citem in cfunc.treeitems:
|
||||
citem = citem.to_specific_type
|
||||
if not (type(citem) == idaapi.cexpr_t and citem.opname in ('memptr', 'memref')):
|
||||
if not (type(citem) == ida_hexrays.cexpr_t and citem.opname in ('memptr', 'memref')):
|
||||
continue
|
||||
|
||||
_x = citem.operands['x']
|
||||
_m = citem.operands['m']
|
||||
_xtype = _x.type
|
||||
_xtype.remove_ptr_or_array()
|
||||
_typename = idaapi.print_tinfo('', 0, 0, idaapi.PRTYPE_1LINE, _xtype, '', '')
|
||||
_typename = ida_typeinf.print_tinfo('', 0, 0, ida_typeinf.PRTYPE_1LINE, _xtype, '', '')
|
||||
|
||||
if not (_typename == typename and _m == m):
|
||||
continue
|
||||
|
||||
parent = citem
|
||||
while parent:
|
||||
if type(parent.to_specific_type) == idaapi.cinsn_t:
|
||||
if type(parent.to_specific_type) == ida_hexrays.cinsn_t:
|
||||
break
|
||||
parent = cfunc.body.find_parent_of(parent)
|
||||
|
||||
@@ -200,7 +202,7 @@ class XrefsForm(idaapi.PluginForm):
|
||||
if parent.ea in addresses:
|
||||
continue
|
||||
|
||||
if parent.ea == idaapi.BADADDR:
|
||||
if parent.ea == ida_idaapi.BADADDR:
|
||||
print('parent.ea is BADADDR')
|
||||
continue
|
||||
|
||||
@@ -209,7 +211,7 @@ class XrefsForm(idaapi.PluginForm):
|
||||
self.functions.append(cfunc.entry_ea)
|
||||
self.items.append((
|
||||
parent.ea,
|
||||
idc.get_func_name(cfunc.entry_ea),
|
||||
ida_funcs.get_func_name(cfunc.entry_ea) or "",
|
||||
self.get_decompiled_line(cfunc, parent.ea)))
|
||||
|
||||
|
||||
@@ -250,13 +252,13 @@ class XrefsForm(idaapi.PluginForm):
|
||||
pass
|
||||
|
||||
|
||||
class show_xrefs_ah_t(idaapi.action_handler_t):
|
||||
class show_xrefs_ah_t(ida_kernwin.action_handler_t):
|
||||
def __init__(self):
|
||||
idaapi.action_handler_t.__init__(self)
|
||||
ida_kernwin.action_handler_t.__init__(self)
|
||||
self.sel = None
|
||||
|
||||
def activate(self, ctx):
|
||||
vu = idaapi.get_widget_vdui(ctx.widget)
|
||||
vu = ida_hexrays.get_widget_vdui(ctx.widget)
|
||||
if not vu or not self.sel:
|
||||
print("No vdui? Strange, since this action should be enabled only for pseudocode views.")
|
||||
return 0
|
||||
@@ -266,32 +268,32 @@ class show_xrefs_ah_t(idaapi.action_handler_t):
|
||||
return 1
|
||||
|
||||
def update(self, ctx):
|
||||
if ctx.widget_type != idaapi.BWN_PSEUDOCODE:
|
||||
return idaapi.AST_DISABLE_FOR_WIDGET
|
||||
vu = idaapi.get_widget_vdui(ctx.widget)
|
||||
vu.get_current_item(idaapi.USE_KEYBOARD)
|
||||
if ctx.widget_type != ida_kernwin.BWN_PSEUDOCODE:
|
||||
return ida_kernwin.AST_DISABLE_FOR_WIDGET
|
||||
vu = ida_hexrays.get_widget_vdui(ctx.widget)
|
||||
vu.get_current_item(ida_hexrays.USE_KEYBOARD)
|
||||
item = vu.item
|
||||
self.sel = None
|
||||
if item.citype == idaapi.VDI_EXPR and item.it.to_specific_type.opname in ('obj', 'memref', 'memptr'):
|
||||
if item.citype == ida_hexrays.VDI_EXPR and item.it.to_specific_type.opname in ('obj', 'memref', 'memptr'):
|
||||
# if an expression is selected. verify that it's either a cot_obj, cot_memref or cot_memptr
|
||||
self.sel = item.it.to_specific_type
|
||||
|
||||
elif item.citype == idaapi.VDI_FUNC:
|
||||
elif item.citype == ida_hexrays.VDI_FUNC:
|
||||
# if the function itself is selected, show xrefs to it.
|
||||
self.sel = item.f
|
||||
|
||||
return idaapi.AST_ENABLE if self.sel else idaapi.AST_DISABLE
|
||||
return ida_kernwin.AST_ENABLE if self.sel else ida_kernwin.AST_DISABLE
|
||||
|
||||
|
||||
class vds_xrefs_hooks_t(idaapi.Hexrays_Hooks):
|
||||
class vds_xrefs_hooks_t(ida_hexrays.Hexrays_Hooks):
|
||||
def populating_popup(self, widget, phandle, vu):
|
||||
idaapi.attach_action_to_popup(widget, phandle, "vdsxrefs:show", None)
|
||||
ida_kernwin.attach_action_to_popup(widget, phandle, "vdsxrefs:show", None)
|
||||
return 0
|
||||
|
||||
|
||||
if idaapi.init_hexrays_plugin():
|
||||
adesc = idaapi.action_desc_t('vdsxrefs:show', 'Show xrefs', show_xrefs_ah_t(), "Ctrl+X")
|
||||
if idaapi.register_action(adesc):
|
||||
if ida_hexrays.init_hexrays_plugin():
|
||||
adesc = ida_kernwin.action_desc_t('vdsxrefs:show', 'Show xrefs', show_xrefs_ah_t(), "Ctrl+X")
|
||||
if ida_kernwin.register_action(adesc):
|
||||
vds_xrefs_hooks = vds_xrefs_hooks_t()
|
||||
vds_xrefs_hooks.hook()
|
||||
else:
|
||||
|
||||
@@ -0,0 +1,357 @@
|
||||
"""
|
||||
summary: logging IDB events
|
||||
|
||||
description:
|
||||
these hooks will be notified about IDB events, and
|
||||
dump their information to the "Output" window
|
||||
"""
|
||||
|
||||
import inspect
|
||||
|
||||
import ida_idp
|
||||
|
||||
class idb_logger_hooks_t(ida_idp.IDB_Hooks):
|
||||
|
||||
def __init__(self):
|
||||
ida_idp.IDB_Hooks.__init__(self)
|
||||
self.inhibit_log = 0;
|
||||
|
||||
def _format_value(self, v):
|
||||
return str(v)
|
||||
|
||||
def _log(self, msg=None):
|
||||
if self.inhibit_log <= 0:
|
||||
if msg:
|
||||
print(">>> idb_logger_hooks_t: %s" % msg)
|
||||
else:
|
||||
stack = inspect.stack()
|
||||
frame, _, _, _, _, _ = stack[1]
|
||||
args, _, _, values = inspect.getargvalues(frame)
|
||||
method_name = inspect.getframeinfo(frame)[2]
|
||||
argstrs = []
|
||||
for arg in args[1:]:
|
||||
argstrs.append("%s=%s" % (arg, self._format_value(values[arg])))
|
||||
print(">>> idb_logger_hooks_t.%s: %s" % (method_name, ", ".join(argstrs)))
|
||||
return 0
|
||||
|
||||
def adding_segm(self, segment):
|
||||
return self._log()
|
||||
|
||||
def allsegs_moved(self, info):
|
||||
return self._log()
|
||||
|
||||
def auto_empty(self):
|
||||
return self._log()
|
||||
|
||||
def auto_empty_finally(self):
|
||||
return self._log()
|
||||
|
||||
def bookmark_changed(self, index, pos, desc, op):
|
||||
return self._log()
|
||||
|
||||
def byte_patched(self, ea, old_value):
|
||||
return self._log()
|
||||
|
||||
def callee_addr_changed(self, ea, callee):
|
||||
return self._log()
|
||||
|
||||
def changing_cmt(self, ea, is_repeatable, new_comment):
|
||||
return self._log()
|
||||
|
||||
def changing_enum_bf(self, tid, new_bf):
|
||||
return self._log()
|
||||
|
||||
def changing_enum_cmt(self, tid, is_repeatable, new_comment):
|
||||
return self._log()
|
||||
|
||||
def changing_op_ti(self, ea, n, new_type, new_fnames):
|
||||
return self._log()
|
||||
|
||||
def changing_op_type(self, ea, n, opinfo):
|
||||
return self._log()
|
||||
|
||||
def changing_range_cmt(self, kind, _range, comment, is_repeatable):
|
||||
return self._log()
|
||||
|
||||
def changing_segm_class(self, segment):
|
||||
return self._log()
|
||||
|
||||
def changing_segm_end(self, segment, new_end, flags):
|
||||
return self._log()
|
||||
|
||||
def changing_segm_name(self, segment, old_name):
|
||||
return self._log()
|
||||
|
||||
def changing_segm_start(self, segment, new_start, flags):
|
||||
return self._log()
|
||||
|
||||
def changing_struc_align(self, sptr):
|
||||
return self._log()
|
||||
|
||||
def changing_struc_cmt(self, tid, is_repeatable, comment):
|
||||
return self._log()
|
||||
|
||||
def changing_struc_member(self, sptr, mptr, flags, ti, nbytes):
|
||||
return self._log()
|
||||
|
||||
def changing_ti(self, ea, new_type, new_fnames):
|
||||
return self._log()
|
||||
|
||||
def closebase(self):
|
||||
return self._log()
|
||||
|
||||
def cmt_changed(self, ea, is_repeatable):
|
||||
return self._log()
|
||||
|
||||
def compiler_changed(self, may_adjust_inf_fields):
|
||||
return self._log()
|
||||
|
||||
def deleting_enum(self, tid):
|
||||
return self._log()
|
||||
|
||||
def deleting_enum_member(self, tid, cid):
|
||||
return self._log()
|
||||
|
||||
def deleting_func(self, pfn):
|
||||
return self._log()
|
||||
|
||||
def deleting_func_tail(self, pfn, tail):
|
||||
return self._log()
|
||||
|
||||
def deleting_segm(self, start_ea):
|
||||
return self._log()
|
||||
|
||||
def deleting_struc(self, sptr):
|
||||
return self._log()
|
||||
|
||||
def deleting_struc_member(self, sptr, mptr):
|
||||
return self._log()
|
||||
|
||||
def deleting_tryblks(self, _range):
|
||||
return self._log()
|
||||
|
||||
def destroyed_items(self, ea1, ea2, will_disable_range):
|
||||
return self._log()
|
||||
|
||||
def determined_main(self, main):
|
||||
return self._log()
|
||||
|
||||
def dirtree_link(self, dt, path, is_link):
|
||||
return self._log()
|
||||
|
||||
def dirtree_mkdir(self, dt, path):
|
||||
return self._log()
|
||||
|
||||
def dirtree_move(self, dt, _from, to):
|
||||
return self._log()
|
||||
|
||||
def dirtree_rank(self, dt, path, rank):
|
||||
return self._log()
|
||||
|
||||
def dirtree_rmdir(self, dt, path):
|
||||
return self._log()
|
||||
|
||||
def dirtree_rminode(self, dt, inode):
|
||||
return self._log()
|
||||
|
||||
def dirtree_segm_moved(self, dt):
|
||||
return self._log()
|
||||
|
||||
def enum_bf_changed(self, tid):
|
||||
return self._log()
|
||||
|
||||
def enum_cmt_changed(self, tid, is_repeatable):
|
||||
return self._log()
|
||||
|
||||
def enum_created(self, tid):
|
||||
return self._log()
|
||||
|
||||
def enum_deleted(self, tid):
|
||||
return self._log()
|
||||
|
||||
def enum_member_created(self, tid, cid):
|
||||
return self._log()
|
||||
|
||||
def enum_member_deleted(self, tid, cid):
|
||||
return self._log()
|
||||
|
||||
def enum_renamed(self, tid):
|
||||
return self._log()
|
||||
|
||||
def expanding_struc(self, sptr, offset, delta):
|
||||
return self._log()
|
||||
|
||||
def extlang_changed(self, kind, el, idx):
|
||||
return self._log()
|
||||
|
||||
def extra_cmt_changed(self, ea, line_idx, comment):
|
||||
return self._log()
|
||||
|
||||
def flow_chart_created(self, fc):
|
||||
return self._log()
|
||||
|
||||
def frame_deleted(self, pfn):
|
||||
return self._log()
|
||||
|
||||
def func_added(self, pfn):
|
||||
return self._log()
|
||||
|
||||
def func_deleted(self, func_ea):
|
||||
return self._log()
|
||||
|
||||
def func_noret_changed(self, pfn):
|
||||
return self._log()
|
||||
|
||||
def func_tail_appended(self, pfn, tail):
|
||||
return self._log()
|
||||
|
||||
def func_tail_deleted(self, pfn, tail_ea):
|
||||
return self._log()
|
||||
|
||||
def func_updated(self, pfn):
|
||||
return self._log()
|
||||
|
||||
def idasgn_loaded(self, sig_name):
|
||||
return self._log()
|
||||
|
||||
def item_color_changed(self, ea, color):
|
||||
return self._log()
|
||||
|
||||
def kernel_config_loaded(self, pass_number):
|
||||
return self._log()
|
||||
|
||||
def loader_finished(self, li, neflags, filetypename):
|
||||
return self._log()
|
||||
|
||||
def local_types_changed(self):
|
||||
return self._log()
|
||||
|
||||
def make_code(self, insn):
|
||||
return self._log()
|
||||
|
||||
def make_data(self, ea, flags, tid, _len):
|
||||
return self._log()
|
||||
|
||||
def op_ti_changed(self, ea, n, _type, fnames):
|
||||
return self._log()
|
||||
|
||||
def op_type_changed(self, ea, n):
|
||||
return self._log()
|
||||
|
||||
def range_cmt_changed(self, kind, _range, comment, is_repeatable):
|
||||
return self._log()
|
||||
|
||||
def renamed(self, ea, new_name, is_local_name, old_name):
|
||||
return self._log()
|
||||
|
||||
def renaming_enum(self, tid, is_enum, new_name):
|
||||
return self._log()
|
||||
|
||||
def renaming_struc(self, tid, old_name, new_name):
|
||||
return self._log()
|
||||
|
||||
def renaming_struc_member(self, sptr, mptr, new_name):
|
||||
return self._log()
|
||||
|
||||
def savebase(self):
|
||||
return self._log()
|
||||
|
||||
def segm_added(self, segment):
|
||||
return self._log()
|
||||
|
||||
def segm_attrs_updated(self, segment):
|
||||
return self._log()
|
||||
|
||||
def segm_class_changed(self, segment, sclass):
|
||||
return self._log()
|
||||
|
||||
def segm_deleted(self, start_ea, end_ea, flags):
|
||||
return self._log()
|
||||
|
||||
def segm_end_changed(self, segment, old_end):
|
||||
return self._log()
|
||||
|
||||
def segm_moved(self, _from, to, size, changed_netmap):
|
||||
return self._log()
|
||||
|
||||
def segm_name_changed(self, segment, name):
|
||||
return self._log()
|
||||
|
||||
def segm_start_changed(self, segment, old_start):
|
||||
return self._log()
|
||||
|
||||
def set_func_end(self, pfn, new_end):
|
||||
return self._log()
|
||||
|
||||
def set_func_start(self, pfn, new_start):
|
||||
return self._log()
|
||||
|
||||
def sgr_changed(self, start_ea, end_ea, regnum, value, old_value, tag):
|
||||
return self._log()
|
||||
|
||||
def sgr_deleted(self, start_ea, end_ea, regnum):
|
||||
return self._log()
|
||||
|
||||
def stkpnts_changed(self, pfn):
|
||||
return self._log()
|
||||
|
||||
def struc_align_changed(self, sptr):
|
||||
return self._log()
|
||||
|
||||
def struc_cmt_changed(self, tid, is_repeatable):
|
||||
return self._log()
|
||||
|
||||
def struc_created(self, tid):
|
||||
return self._log()
|
||||
|
||||
def struc_deleted(self, tid):
|
||||
return self._log()
|
||||
|
||||
def struc_expanded(self, sptr):
|
||||
return self._log()
|
||||
|
||||
def struc_member_changed(self, sptr, mptr):
|
||||
return self._log()
|
||||
|
||||
def struc_member_created(self, sptr, mptr):
|
||||
return self._log()
|
||||
|
||||
def struc_member_deleted(self, sptr, mid, offset):
|
||||
return self._log()
|
||||
|
||||
def struc_member_renamed(self, sptr, mptr):
|
||||
return self._log()
|
||||
|
||||
def struc_renamed(self, sptr, success):
|
||||
return self._log()
|
||||
|
||||
def tail_owner_changed(self, tail, owner_func, old_owner):
|
||||
return self._log()
|
||||
|
||||
def thunk_func_created(self, pfn):
|
||||
return self._log()
|
||||
|
||||
def ti_changed(self, ea, _type, fnames):
|
||||
return self._log()
|
||||
|
||||
def tryblks_updated(self, tbv):
|
||||
return self._log()
|
||||
|
||||
def updating_tryblks(self, tbv):
|
||||
return self._log()
|
||||
|
||||
def upgraded(self, _from):
|
||||
return self._log()
|
||||
|
||||
def enum_width_changed(self, tid, width):
|
||||
return self._log()
|
||||
|
||||
def enum_flag_changed(self, tid, flags):
|
||||
return self._log()
|
||||
|
||||
def enum_ordinal_changed(self, tid, ordinal):
|
||||
return self._log()
|
||||
|
||||
|
||||
idb_hooks = idb_logger_hooks_t()
|
||||
idb_hooks.hook()
|
||||
@@ -0,0 +1,70 @@
|
||||
"""
|
||||
summary: notify the user when an instruction operand changes
|
||||
|
||||
description:
|
||||
Show notifications whenever the user changes
|
||||
an instruction's operand, or a data item.
|
||||
"""
|
||||
|
||||
import binascii
|
||||
|
||||
import ida_idp
|
||||
import ida_bytes
|
||||
import ida_nalt
|
||||
import ida_struct
|
||||
import ida_enum
|
||||
|
||||
class operand_changed_t(ida_idp.IDB_Hooks):
|
||||
def log(self, msg):
|
||||
print(">>> %s" % msg)
|
||||
|
||||
def op_type_changed(self, ea, n):
|
||||
flags = ida_bytes.get_flags(ea)
|
||||
self.log("op_type_changed(ea=0x%08X, n=%d). Flags now: 0x%08X" % (ea, n, flags))
|
||||
|
||||
buf = ida_nalt.opinfo_t()
|
||||
opi = ida_bytes.get_opinfo(buf, ea, n, flags)
|
||||
if opi:
|
||||
if ida_bytes.is_struct(flags):
|
||||
self.log("New struct: 0x%08X (name=%s)" % (
|
||||
opi.tid,
|
||||
ida_struct.get_struc_name(opi.tid)))
|
||||
elif ida_bytes.is_strlit(flags):
|
||||
encidx = ida_nalt.get_str_encoding_idx(opi.strtype)
|
||||
if encidx == ida_nalt.STRENC_DEFAULT:
|
||||
encidx = ida_nalt.get_default_encoding_idx(ida_nalt.get_strtype_bpu(opi.strtype))
|
||||
encname = ida_nalt.get_encoding_name(encidx)
|
||||
strlen = ida_bytes.get_max_strlit_length(
|
||||
ea,
|
||||
opi.strtype,
|
||||
ida_bytes.ALOPT_IGNHEADS | ida_bytes.ALOPT_IGNCLT)
|
||||
raw = ida_bytes.get_strlit_contents(ea, strlen, opi.strtype) or b""
|
||||
self.log("New strlit: 0x%08X, raw hex=%s (encoding=%s)" % (
|
||||
opi.strtype,
|
||||
binascii.hexlify(raw),
|
||||
encname))
|
||||
elif ida_bytes.is_off(flags, n):
|
||||
self.log("New offset: refinfo={target=0x%08X, base=0x%08X, tdelta=0x%08X, flags=0x%X}" % (
|
||||
opi.ri.target,
|
||||
opi.ri.base,
|
||||
opi.ri.tdelta,
|
||||
opi.ri.flags))
|
||||
elif ida_bytes.is_enum(flags, n):
|
||||
self.log("New enum: 0x%08X (enum=%s), serial=%d" % (
|
||||
opi.ec.tid,
|
||||
ida_enum.get_enum_name(opi.ec.tid),
|
||||
opi.ec.serial))
|
||||
pass
|
||||
elif ida_bytes.is_stroff(flags, n):
|
||||
parts = []
|
||||
for i in range(opi.path.len):
|
||||
tid = opi.path.ids[i]
|
||||
parts.append("0x%08X (name=%s)" % (tid, ida_struct.get_struc_name(tid)))
|
||||
self.log("New stroff: path=[%s] (len=%d, delta=0x%08X)" % (
|
||||
", ".join(parts),
|
||||
opi.path.len,
|
||||
opi.path.delta))
|
||||
elif ida_bytes.is_custom(flags) or ida_bytes.is_custfmt(flags, n):
|
||||
self.log("New custom data type") # unimplemented
|
||||
else:
|
||||
print("Cannot retrieve opinfo_t")
|
||||
@@ -0,0 +1,81 @@
|
||||
"""
|
||||
summary: Record and replay changes in function prototypes
|
||||
|
||||
description:
|
||||
This is a sample script, that will record (in memory) all changes in
|
||||
functions prototypes, in order to re-apply them later.
|
||||
|
||||
To use this script:
|
||||
- open an IDB (say, "test.idb")
|
||||
- modify some functions prototypes (e.g., by triggering the 'Y'
|
||||
shortcut when the cursor is placed on the first address of a
|
||||
function)
|
||||
- reload that IDB, *without saving it first*
|
||||
- call rpc.replay(), to re-apply the modifications.
|
||||
|
||||
Note: 'ti_changed' is also called for changes to the function
|
||||
frames, but we'll only record function prototypes changes.
|
||||
"""
|
||||
import ida_idp
|
||||
import ida_funcs
|
||||
import ida_typeinf
|
||||
|
||||
class replay_prototypes_changes_t(ida_idp.IDB_Hooks):
|
||||
def __init__(self):
|
||||
ida_idp.IDB_Hooks.__init__(self)
|
||||
# we'll store tuples (ea, typ, fields). We cannot store
|
||||
# tinfo_t instances in there, because tinfo_t's are only
|
||||
# valid while the IDB is opened.
|
||||
# Since the very purpose of this example is to re-apply
|
||||
# types after the IDB has been closed & re-opened, we
|
||||
# must therefore keep the serialized version only.
|
||||
self.memo = []
|
||||
self.replaying = False
|
||||
|
||||
def _deser(self, typ, fields):
|
||||
tif = ida_typeinf.tinfo_t()
|
||||
if not tif.deserialize(ida_typeinf.get_idati(), typ, fields):
|
||||
tif = None
|
||||
return tif
|
||||
|
||||
def ti_changed(self, ea, typ, fields):
|
||||
if not self.replaying:
|
||||
pfn = ida_funcs.get_func(ea)
|
||||
if pfn and pfn.start_ea == ea:
|
||||
self.memo.append((ea, typ, fields))
|
||||
|
||||
# de-serialize, just for the sake of printing
|
||||
tif = self._deser(typ, fields)
|
||||
if tif:
|
||||
print("%x: type changed: %s" % (
|
||||
ea,
|
||||
tif._print(None, ida_typeinf.PRTYPE_1LINE)))
|
||||
|
||||
def replay(self):
|
||||
self.replaying = True
|
||||
try:
|
||||
for ea, typ, fields in self.memo:
|
||||
tif = self._deser(typ, fields)
|
||||
if tif:
|
||||
print("%x: applying type: %s" % (
|
||||
ea,
|
||||
tif._print(None, ida_typeinf.PRTYPE_1LINE)))
|
||||
# Since that type information was remembered from a change
|
||||
# the user made, we'll re-apply it as a definite type (i.e.,
|
||||
# can't be overriden by IDA's auto-analysis/heuristics.)
|
||||
apply_flags = ida_typeinf.TINFO_DEFINITE
|
||||
if not ida_typeinf.apply_tinfo(ea, tif, apply_flags):
|
||||
print("FAILED")
|
||||
finally:
|
||||
self.replaying = False
|
||||
|
||||
rpc = replay_prototypes_changes_t()
|
||||
if rpc.hook():
|
||||
print("""
|
||||
Please modify some functions prototypes (press 'Y' when the
|
||||
cursor is on the function name, or first address), and when
|
||||
you are done reload this IDB, *WITHOUT* saving it first,
|
||||
and type 'rpc.replay()'
|
||||
""")
|
||||
else:
|
||||
print("Couldn't create hooks")
|
||||
Binary file not shown.
@@ -1,32 +1,44 @@
|
||||
"""
|
||||
summary: override some parts of the processor module
|
||||
|
||||
description:
|
||||
Implements disassembly of BUG_INSTR used in Linux kernel
|
||||
BUG() macro, which is architecturally undefined and is not
|
||||
disassembled by IDA's ARM module
|
||||
|
||||
See Linux/arch/arm/include/asm/bug.h for more info
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
# this script implements disassembly of BUG_INSTR used in Linux kernel BUG() macro
|
||||
# normally it's architecturally undefined and is not disassembled by IDA's ARM module
|
||||
# see Linux/arch/arm/include/asm/bug.h
|
||||
|
||||
import idaapi
|
||||
import ida_idp
|
||||
import ida_bytes
|
||||
import ida_segregs
|
||||
|
||||
ITYPE_BUGINSN = idaapi.CUSTOM_CMD_ITYPE + 10
|
||||
ITYPE_BUGINSN = ida_idp.CUSTOM_INSN_ITYPE + 10
|
||||
MNEM_WIDTH = 16
|
||||
|
||||
class MyHooks(idaapi.IDP_Hooks):
|
||||
class MyHooks(ida_idp.IDP_Hooks):
|
||||
|
||||
def __init__(self):
|
||||
idaapi.IDP_Hooks.__init__(self)
|
||||
ida_idp.IDP_Hooks.__init__(self)
|
||||
self.reported = []
|
||||
|
||||
def ev_ana_insn(self, insn):
|
||||
t = get_sreg(insn.ea, "T")
|
||||
if t==0 and get_wide_dword(insn.ea) == 0xE7F001F2:
|
||||
t_reg = ida_idp.str2reg("T")
|
||||
t = ida_segregs.get_sreg(insn.ea, t_reg)
|
||||
if t==0 and ida_bytes.get_wide_dword(insn.ea) == 0xE7F001F2:
|
||||
insn.itype = ITYPE_BUGINSN
|
||||
insn.size = 4
|
||||
elif t!=0 and get_wide_word(insn.ea) == 0xde02:
|
||||
elif t!=0 and ida_bytes.get_wide_word(insn.ea) == 0xde02:
|
||||
insn.itype = ITYPE_BUGINSN
|
||||
insn.size = 2
|
||||
return insn.size
|
||||
|
||||
def ev_emu_insn(self, insn):
|
||||
if insn.ea == ITYPE_BUGINSN:
|
||||
return 1
|
||||
if insn.itype == ITYPE_BUGINSN:
|
||||
return 1 # do not add any xrefs (stop code flow)
|
||||
# use default processing for all other functions
|
||||
return 0
|
||||
|
||||
def ev_out_mnem(self, outctx):
|
||||
@@ -35,10 +47,9 @@ class MyHooks(idaapi.IDP_Hooks):
|
||||
return 1
|
||||
return 0
|
||||
|
||||
if idaapi.ph.id == idaapi.PLFM_ARM:
|
||||
if ida_idp.ph.id == ida_idp.PLFM_ARM:
|
||||
bahooks = MyHooks()
|
||||
bahooks.hook()
|
||||
print("BUG_INSTR processor extension installed")
|
||||
else:
|
||||
warning("This script only supports ARM files")
|
||||
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
"""
|
||||
summary: an `ida_idp.IDP_Hooks.assembly` implementation
|
||||
|
||||
description:
|
||||
We add support for assembling the following pseudo instructions:
|
||||
|
||||
* "zero eax" -> xor eax, eax
|
||||
* "nothing" -> nop
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import idaapi
|
||||
import ida_idp
|
||||
import idautils
|
||||
|
||||
"""
|
||||
This is a sample script for extending the assemble() hook.
|
||||
|
||||
We add support for assembling the following pseudo instructions:
|
||||
- "zero eax" -> xor eax, eax
|
||||
- "nothing" -> nop
|
||||
|
||||
|
||||
(c) Hex-Rays
|
||||
"""
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
class assemble_idp_hook_t(idaapi.IDP_Hooks):
|
||||
class assemble_idp_hook_t(ida_idp.IDP_Hooks):
|
||||
def ev_assemble(self, ea, cs, ip, use32, line):
|
||||
line = line.strip()
|
||||
if line == "zero eax":
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
body
|
||||
{
|
||||
margin: 3%;
|
||||
}
|
||||
|
||||
.exp-col
|
||||
{
|
||||
cursor: pointer;
|
||||
padding: 0 4px 0 6px;
|
||||
}
|
||||
|
||||
.collapsed-entry .details
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.example-entry .details
|
||||
{
|
||||
margin-left: 3%;
|
||||
padding: 6px;
|
||||
background-color: #eef;
|
||||
}
|
||||
|
||||
a
|
||||
{
|
||||
text-decoration: none;
|
||||
}
|
||||
+4386
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,72 @@
|
||||
|
||||
function on_see_also(see_also)
|
||||
{
|
||||
var idx = see_also.indexOf("#");
|
||||
if ( idx > -1 )
|
||||
see_also = see_also.substring(idx+1,see_also.length);
|
||||
var entry = find_entry_el(document.getElementById('DIV_' + see_also));
|
||||
if ( entry )
|
||||
{
|
||||
set_entry_state(entry, true);
|
||||
entry.scrollIntoView();
|
||||
}
|
||||
}
|
||||
|
||||
function find_parent_with_class(el, klass)
|
||||
{
|
||||
while ( el )
|
||||
{
|
||||
if ( el.className && el.className.indexOf(klass) > -1 )
|
||||
return el;
|
||||
el = el.parentNode;
|
||||
}
|
||||
}
|
||||
|
||||
function find_child_with_class(el, klass)
|
||||
{
|
||||
return el.querySelector("." + klass);
|
||||
}
|
||||
|
||||
function find_entry_el(el) { return find_parent_with_class(el, "example-entry"); }
|
||||
function find_expander(entry_el) { return find_child_with_class(entry_el, "expander"); }
|
||||
function find_collapser(entry_el) { return find_child_with_class(entry_el, "collapser"); }
|
||||
|
||||
function set_entry_state(entry_el, expanded)
|
||||
{
|
||||
var collapser_el = find_collapser(entry_el);
|
||||
var expander_el = find_expander(entry_el);
|
||||
collapser_el.style.display = expanded ? "" : "none";
|
||||
expander_el.style.display = expanded ? "none" : "";
|
||||
if ( expanded )
|
||||
entry_el.classList.remove("collapsed-entry");
|
||||
else
|
||||
entry_el.classList.add("collapsed-entry");
|
||||
}
|
||||
|
||||
function handle_click(e)
|
||||
{
|
||||
e = e || window.event;
|
||||
var el = e.target || e.srcElement;
|
||||
var entry_el = find_entry_el(el);
|
||||
var ok = false;
|
||||
if ( el.classList.contains("collapser") )
|
||||
set_entry_state(entry_el, false);
|
||||
else if ( el.classList.contains("expander") )
|
||||
set_entry_state(entry_el, true);
|
||||
else if ( el.classList.contains("ex_link") ) // see also
|
||||
on_see_also(el.href);
|
||||
else
|
||||
return;
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
function handle_toplevel_action(e)
|
||||
{
|
||||
e = e || window.event;
|
||||
var el = e.target || e.srcElement;
|
||||
var expanded = el.classList.contains("expand-all");
|
||||
var els = document.getElementsByClassName("example-entry");
|
||||
for ( var idx = 0, n = els.length; idx < n; ++idx )
|
||||
set_entry_state(els[idx], expanded);
|
||||
e.stopPropagation();
|
||||
}
|
||||
+3648
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user