IDA plugins used to be small scripts that ran inside one analyst's session. Today many are products in their own right: add-ons with their own UI, headless tools built on idat or idalib, and pipelines that run IDA on a license shared by a whole team. All of them depend on what the IDA underneath is licensed for. Is the ARM64 decompiler included? Is Lumina? Is there a usable license at all? And what if you need a different one?
Until now, IDA had no supported way to answer these questions from code, and we kept seeing new workarounds to fill the gap. IDA 9.5 gives you one: a licensing API that answers all of them, and lets you act on the answers.
What’s New
Code built on the IDA API can now read and change IDA's licensing state: inspect the active license, check whether an add-on is available, or switch to a different license entirely. It comes as a License class in the C++ SDK and IDAPython, and as a license module in IDA Domain.
The API covers three jobs.
Reading the License
Start with the basics of the active license: its id, product and edition, whether it is usable, when its activation period ends, and which add-ons it includes.
lic = ida_license.License()
print(f"License {lic.id}: {lic.product} ({lic.edition})")
print(f"Usable: {lic.valid}")
if lic.end:
print(f"Activation period ends: {datetime.date.fromtimestamp(lic.end)}")
for code in lic.add_ons:
print(f"Usable add-on: {code}")
License XX-XXXX-XXXX-XX: IDAXXX (ida-XXX)
Usable: True
Activation period ends: 20XX-XX-XX
Usable add-on: HEXX64
Usable add-on: HEXARM64
Checking What You Can Use
This is the part most plugins care about: is the feature I need actually available? has_add_on() answers that, using the same product codes you see in the License Manager, such as HEXARM64 or TEAMS. The answer already accounts for everything: whether the license is still valid, whether the add-on's own period has run out, and, for a floating license, whether this IDA currently holds a seat. One question, one yes or no.
Python>lic.valid
True
Python>lic.has_add_on("HEXX64")
True
Python>lic.decompiler_available
True
Python>lic.has_add_on("TEAMS")
False
For the most common question there is a shortcut: decompiler_available tells you whether the open database can be decompiled at all, whatever its architecture.
Switching Licenses
You can also change the license source at run time, pointing IDA at a license file or a license server, and activate any license that source offers.
def checkout_with(add_on):
lic = ida_license.License()
if lic.has_add_on(add_on):
return True
for lid in lic.source_ids:
if lid != lic.id and lic.checkout(lid) and lic.has_add_on(add_on):
return True
return False
In short, everything the License Manager dialog shows and does is now available from code.
The full API will be documented at docs.hex-rays.com at release time, and the SDK ships two complete examples: src/plugins/licinfo/licinfo.cpp and src/plugins/idapython/examples/misc/print_license_info.py.
Why It Matters
With the license state fully scriptable, your tools can react to it instead of guessing. That matters most for plugins with several features, headless analysis scripts and shared automation.
Plugins can offer only what the license supports, instead of failing when a user reaches for it:
lic = ida_license.License()
if lic.has_add_on("TEAMS"):
ida_kernwin.register_action(lumina_related_action)
Headless scripts can check their requirements up front and fail with a clear message before doing any work:
lic = ida_license.License()
if not lic.valid:
raise SystemExit("no usable IDA license")
if not lic.has_add_on("HEXX64"):
raise SystemExit("the x64 decompiler is not part of this license")
Automated pipelines can manage licenses properly, without workarounds. Picture a pool of floating licenses shared by several workers, where each worker finds a license with the add-on it needs, uses it, and hands it back:
# search through available licenses in the pool and find one that has the required add-on
def checkout_with(add_on):
lic = ida_license.License()
if lic.has_add_on(add_on):
return True
for lid in lic.source_ids:
if lid != lic.id and lic.checkout(lid) and lic.has_add_on(add_on):
return True
return Falselic = ida_license.License()
if not lic.set_server("licsrv.example.com", 65434, True): # True: use TLS
raise SystemExit("license server unreachable or no seat available")
try:
if not checkout_with(lic, "HEXARM64"):
raise SystemExit("no license with the ARM64 decompiler is free right now")
# analysis ...
finally:
lic.checkin() # immediately return the license to make it available for the rest of the group
You could even add a check that warns you before a license expires. The point is simple: anything license related can now happen in code, the same code that does the actual work. We hope this removes friction for everyone building on the IDA API, and retires the hacks people have relied on until now.
Behind the Scenes
People were rebuilding parts of this long before IDA offered it. Not for fun: a plugin has to decide what it can offer, and a headless tool has to know whether it can run at all. Some hacks people resorted to:
- conflating the return value of
init_hexrays_plugin()with "is the decompiler licensed" - searching for
idaXXX_*.hexlicin the user directory to guess the capabilities of the IDA install based on the edition of the licenses
And our favorite:
- reverse engineering libida's license manager (shoutout)
Each of those can now be properly queried from IDA with one call: has_add_on("HEXX64") / decompiler_available, edition, valid.
If that was you, good news: you can go back to reverse engineering your samples instead of IDA. :)
Where You’ll Find It
The licensing API is available in the IDA 9.5 C++ SDK, in IDAPython, and in IDA Domain.
Try It Out
IDA 9.5 is currently in beta and available from the customer portal at https://my.hex-rays.com. If you maintain a plugin or pipeline that works around licensing today, we would love to hear how the new API fits. Share your feedback on the community forum or through support.