Skip to main content

Headless IDA with multi-instance support

Project description

Headless IDA

Headless IDA Multi

Latest Release PyPI Statistics License

Install

NOTE: This is a modified version of Headless IDA with multi-instance support.

To install this modified package, run:

pip install git+https://github.com/Taardisaa/headless-ida-multi.git

Usage

[!TIP] Headless IDA supports the latest idalib. Just provide the idalib path instead of idat64 to use it as the backend.

Use it as a normal Python module.

NOTE: This works only when there is only one HeadlessIda instance in the process. For multiple instances, this will probably break. To isolate interactions with different instances, please use the Remote Exec/Eval/Remoteify features described later.

# Initialize HeadlessIda
from headless_ida_multi import HeadlessIda
headlessida = HeadlessIda("/path/to/idat64", "/path/to/binary")

# Import IDA Modules (make sure you have initialized HeadlessIda first)
import idautils
import ida_name

# Or Import All IDA Modules at Once (idaapi is not imported by default)
# from headless_ida_multi.ida_headers import *

# Have Fun
for func in idautils.Functions():
    print(f"{hex(func)} {ida_name.get_ea_name(func)}")

Persist the IDA Database

By default, Headless IDA uses a temporary database that is deleted when the session ends. To save the database to a specific location, use the idb_path parameter:

from headless_ida_multi import HeadlessIda

# Save the database to a custom location
headlessida = HeadlessIda(
    "/path/to/idat64",
    "/path/to/binary",
    idb_path="/path/to/output.i64"
)

# The database will be saved to /path/to/output.i64 when clean_up() is called
# Parent directories are created automatically if they don't exist

Load a Zipped IDA Database

You can pass a zipped IDA database (.idb.zip or .i64.zip) directly as binary_path. The zip is extracted to a temporary directory, loaded, and cleaned up automatically on exit:

from headless_ida_multi import HeadlessIda

headlessida = HeadlessIda(
    "/path/to/idat64",
    "/path/to/database.i64.zip"
)

# Use IDA as usual — the database is extracted and loaded transparently
import idautils
print(list(idautils.Functions())[0:10])

# Temp directory is cleaned up when clean_up() is called or on exit

Use it as a command line tool.

# Interactive Console
$ headless-ida /path/to/idat64 /path/to/binary
Python 3.8.10 (default, Nov 14 2022, 12:59:47)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> import idautils
>>> list(idautils.Functions())[0:10]
[16384, 16416, 16432, 16448, 16464, 16480, 16496, 16512, 16528, 16544]
>>>


# Run IDAPython Script
$ headless-ida /path/to/idat64 /path/to/binary idascript.py


# One-liner
$ headless-ida /path/to/idat64 /path/to/binary -c "import idautils; print(list(idautils.Functions())[0:10])"


# In case you like IPython
$ headless-ida /path/to/idat64 /path/to/binary -c "import IPython; IPython.embed();"

Remote Exec/Eval/Remoteify

Referenced from https://github.com/justfoxing/jfx_bridge.

def ida_remote_print_all_funcs():
    import idautils # type: ignore
    import ida_name # type: ignore
    for func in idautils.Functions():
        print(f"{hex(func)} {ida_name.get_ea_name(func)}")
    pass


def ida_remote_get_all_func_names():
    import idautils # type: ignore
    import ida_name # type: ignore
    func_names = []
    for func in idautils.Functions():
        func_names.append(ida_name.get_ea_name(func))
    return func_names

headless_ida = HeadlessIda(ida_dir=ida_dir_path, binary_path=bin_path)

print(headless_ida.remote_eval("1+1"))  # 2

if remote_fn := headless_ida.remoteify(ida_remote_get_all_func_names):
    all_funcs = remote_fn()
    all_funcs = list(all_funcs)
    print(all_funcs)
    pass

Support for multiple headless-ida instances

This modified version supports running multiple HeadlessIda instances simultaneously by allocating separate RPyC connections for each instance.

However, this enhancement imposes a constraint: direct use of IDA APIs is no longer feasible. All interactions must be performed via remoteify or remote_* calls to prevent cross-instance conflicts.

Potential Issue: Currently, there is also a potential issue with race conditions. While we use locks to prevent multiple HeadlessIda instances from allocating on the same port, there is still a small chance of port conflicts if some other external process occupies the port between the time we check for availability and the time we bind to it. However, such cases are rare in practice.

headless_ida = HeadlessIda(ida_dir=ida_dir_path, binary_path=bin_path)
headless_ida2 = HeadlessIda(ida_dir=ida_dir_path, binary_path=bin_path_2)

print("-----")
if remote_fn := headless_ida.remoteify(ida_remote_get_all_func_names):
    all_funcs = remote_fn()
    print(all_funcs)

print("-----")
if remote_fn2 := headless_ida2.remoteify(ida_remote_get_all_func_names):
    all_funcs2 = remote_fn2()
    print(all_funcs2)

Advanced Usage

Remote Server

Start a Headless IDA server

$ headless-ida-server /path/to/idat64 localhost 1337 &

Connect to the server in Python script

# Initialize HeadlessIda
from headless_ida_multi import HeadlessIdaRemote
headlessida = HeadlessIdaRemote("localhost", 1337, "/path/to/local/binary")

# Import IDA Modules (make sure you have initialized HeadlessIda first)
import idautils
import ida_name

# Have Fun
for func in idautils.Functions():
    print(f"{hex(func)} {ida_name.get_ea_name(func)}")

Connect to the server in command line

# Interactive Console
$ headless-ida localhost:1337 /path/to/local/binary
# Run IDAPython Script
$ headless-ida localhost:1337 /path/to/local/binary idascript.py
# One-liner
$ headless-ida localhost:1337 /path/to/local/binary -c "import idautils; print(list(idautils.Functions())[0:10])"

Resources

Known Issues

from XXX import *

  • Using from XXX import * syntax with certain ida modules (like idaapi, ida_ua, etc.) is currently unsupported due to SWIG and RPyC compatibility issues. We recommend importing specific items with from XXX import YYY, ZZZ, or importing the entire module using import XXX.
  • The issue arises because SWIG, employed for creating Python bindings for C/C++ code, generates intermediary objects (SwigVarlink) that RPyC, our remote procedure call mechanism, cannot serialize or transmit correctly.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

headless_ida_multi-1.0.1.tar.gz (194.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

headless_ida_multi-1.0.1-py3-none-any.whl (21.1 kB view details)

Uploaded Python 3

File details

Details for the file headless_ida_multi-1.0.1.tar.gz.

File metadata

  • Download URL: headless_ida_multi-1.0.1.tar.gz
  • Upload date:
  • Size: 194.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for headless_ida_multi-1.0.1.tar.gz
Algorithm Hash digest
SHA256 61698fbbd8ad1ccde0a1ee715338b2888bac9f360c74be4cf3e8b5ef93931015
MD5 88ad34a0c4cc12c9c8a0b48a7dda03ae
BLAKE2b-256 2528e4ea934c1c6ee50fae019dfcaaf0c0774931d8b0261e9d46dcd84febf575

See more details on using hashes here.

Provenance

The following attestation bundles were made for headless_ida_multi-1.0.1.tar.gz:

Publisher: pypi.yml on Taardisaa/headless-ida-multi

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file headless_ida_multi-1.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for headless_ida_multi-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d820af5ffe04298f5dc8e9bc0394dc7aef8b9c1be510ae4f4098c8f04998ddd7
MD5 facc5f8b48a1cb5f5764c3d3b87489e5
BLAKE2b-256 f2c8983ea447b5b35d04945897c0bb837fb220034d7270a393869cccfedaf737

See more details on using hashes here.

Provenance

The following attestation bundles were made for headless_ida_multi-1.0.1-py3-none-any.whl:

Publisher: pypi.yml on Taardisaa/headless-ida-multi

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page