| name | analyze-with-ida-domain-api |
| description | Analyze binaries using IDA Pro's Python Domain API (ida-domain) in headless mode (idalib). Use when examining program structure, functions, disassembly, cross-references, or strings without the GUI. |
IDA Pro Headless Analysis with Domain API and idalib
Use this skill to analyze binary files with IDA Pro's Domain API in headless mode.
Setup
The following are already installed and licensed:
- IDA Pro
- idalib (
pip install idapro)
- IDA Domain API (
pip install ida-domain)
You're already ready to go, and you can check by doing:
python3 -c "import ida_domain"
Use the IDA Domain API
Always prefer the IDA Domain API over the legacy low-level IDA Python SDK. The Domain API provides a clean, Pythonic interface that is easier to use and understand.
Documentation Resources
Available API modules: bytes, comments, database, entries, flowchart, functions, heads, hooks, instructions, names, operands, segments, signature_files, strings, types, xrefs
To fetch specific API documentation, use URLs like:
https://ida-domain.docs.hex-rays.com/ref/functions/index.md - Function analysis API
https://ida-domain.docs.hex-rays.com/ref/xrefs/index.md - Cross-reference API
https://ida-domain.docs.hex-rays.com/ref/strings/index.md - String analysis API
Opening a Database
from ida_domain import Database
from ida_domain.database import IdaCommandOptions
ida_options = IdaCommandOptions(auto_analysis=True, new_database=False)
with Database.open("path/to/binary", ida_options, save_on_close=True) as db:
pass
Key Database Properties
with Database.open(path, ida_options) as db:
db.minimum_ea
db.maximum_ea
db.metadata
db.architecture
db.functions
db.strings
db.segments
db.names
db.entries
db.types
db.comments
db.xrefs
db.bytes
db.instructions
Common Analysis Tasks
List functions:
for func in db.functions:
name = db.functions.get_name(func)
print(f"{hex(func.start_ea)}: {name} ({func.size} bytes)")
Get function disassembly and pseudocode:
func = next(f for f in db.functions if db.functions.get_name(f) == "main")
for line in db.functions.get_disassembly(func):
print(line)
try:
for line in db.functions.get_pseudocode(func):
print(line)
except RuntimeError as e:
print(f"Decompilation unavailable: {e}")
Find strings:
for s in db.strings:
print(f"{hex(s.address)}: {s}")
Cross-references:
for xref in db.xrefs.to_ea(target_addr):
print(f"Referenced from {hex(xref.from_ea)} (type: {xref.type.name})")
for xref in db.xrefs.from_ea(source_addr):
print(f"References {hex(xref.to_ea)}")
for xref in db.xrefs.calls_to_ea(func_addr):
print(f"Called from {hex(xref.from_ea)}")
Read bytes:
byte_val = db.bytes.get_byte_at(addr)
dword_val = db.bytes.get_dword_at(addr)
disasm = db.bytes.get_disassembly_at(addr)
Exploring the API at Runtime
You can always ask a subagent to explore the IDA Domain documentation website to learn how to do a task.
Or you can ask a subagent to explore the API at runtime using introspection (esp. docstrings):
import inspect
from ida_domain import Database
from ida_domain.functions import Functions
for name, method in inspect.getmembers(Functions, predicate=inspect.isfunction):
if not name.startswith('_'):
print(f"{name}: {inspect.signature(method)}")
print(Functions.get_pseudocode.__doc__)
with Database.open(path, ida_options) as db:
print([attr for attr in dir(db) if not attr.startswith('_')])
Analysis Methodology
Write and execute small, focused programs rather than reading large amounts of data from the binary. This approach is more efficient and produces better results:
- Form a hypothesis about what you're looking for
- Design a program to gather the minimum data needed to test the hypothesis
- Execute the program via the Bash tool and analyze the results
- Iterate based on findings
Example: Investigating a suspicious function
Instead of dumping all disassembly, write targeted scripts:
from ida_domain import Database
from ida_domain.database import IdaCommandOptions
ida_options = IdaCommandOptions(auto_analysis=True, new_database=False)
with Database.open("sample.exe", ida_options, save_on_close=True) as db:
for s in db.strings:
if "password" in str(s).lower():
print(f"\nString at {hex(s.address)}: {s}")
for xref in db.xrefs.to_ea(s.address):
print(f" Referenced from {hex(xref.from_ea)}")
with Database.open("sample.exe", ida_options, save_on_close=True) as db:
target_addr = 0x401234
for func in db.functions:
if func.start_ea <= target_addr < func.end_ea:
print(f"Function: {db.functions.get_name(func)}")
print(f"Signature: {db.functions.get_signature(func)}")
try:
print("\nPseudocode:")
for line in db.functions.get_pseudocode(func):
print(f" {line}")
except RuntimeError:
print("\nDisassembly (decompiler unavailable):")
for line in db.functions.get_disassembly(func):
print(f" {line}")
break
Performance Tips
- Enable auto_analysis=True on first open to let IDA analyze the binary
- Use save_on_close=True to persist the analysis database (.idb/.i64)
Legacy API (Avoid)
The legacy idc, idautils, ida_funcs APIs still work but are harder to use. Prefer the Domain API for new analysis scripts. Only use legacy APIs when Domain API doesn't expose needed functionality.