IDA as a library (idalib) allows you to use the C++ and IDA Python APIs outside IDA as standalone applications. That way, IDA's engine is used inside your app, which simplifies development with the IDA APIs, which can be done now from your IDE of choice.
Prerequisites
IDA Pro 9.0 or newer installed and running
Installation for C++
To use the ida library from the C++, please refer to the idalib.hpp header file shipped with C++ SDK where you will find the relevant information.
Installation for Python
To use the ida library Python module, you need to install and configure idapro package by following these steps:
Install ida library Python module
Navigate to the idalib/python folder within the IDA Pro installation directory
Run the command: pip install .
When setting up idalib to work with IDA Feeds and your virtual environment (venv), make sure to run the above command from within your activated venv.
Setting up the ida library Python module
Run the Activation Script
You need to inform the idapro Python module of your IDA Pro installation. To do this, run the py-activate-idalib.py script located in your IDA Pro installation folder, or inside the idalib/python folder (depends on the system version you use):
If the -d option is omitted, the script will automatically select the IDA installation folder from which it was executed.
Using the ida library Python module
Import idapro in your script
Make sure to import the idapro package as the first import in your Python script
After importing, you can utilize the existing ida Python APIs
Example script
For a reference on how to use the ida module, check the idalib/examples folder in your IDA Pro installation directory or look at the sample script provided below.
#!/usr/bin/env python3import argparseimport osimport jsonimport idaprofrom pathlib import Pathimport ida_segmentimport ida_idaapiimport ida_funcsimport ida_idpimport ida_autoimport ida_undoclasssig_hooks_t(ida_idp.IDB_Hooks):def__init__(self): ida_idp.IDB_Hooks.__init__(self) self.matched_funcs =set()deffunc_added(self,pfn): self.matched_funcs.add(pfn.start_ea)deffunc_deleted(self,func_ea):try: self.matched_funcs.remove(func_ea)except:passdeffunc_updated(self,pfn): self.matched_funcs.add(pfn.start_ea)defidasgn_loaded(self,sig_name):returnprint(f"Sig {sig_name} loaded")defdump_matches(self):for fea in self.matched_funcs:print(f"Matched function {ida_funcs.get_func_name(fea)}")### List the segments for the loaded binarydeflist_segments(): nb_items = ida_segment.get_segm_qty()print("Segments number:", nb_items)for i inrange(0, nb_items): seg_src = ida_segment.getnseg(i)print(str(i+1) +".")print("\tname:", ida_segment.get_segm_name(seg_src))print("\tstart_address:", hex(seg_src.start_ea))print("\tend_address", hex(seg_src.end_ea))print("\tis_data_segment:", ida_segment.get_segm_class(seg_src) == ida_segment.SEG_DATA)print("\tbitness:", seg_src.bitness)print("\tpermissions:", seg_src.perm, "\n")### Just call an existing python scriptdefrun_script(script_file_name:str):ifnot os.path.isfile(script_file_name):print(f"The specified script file {script_file_name} is not a valid python script")return ida_idaapi.IDAPython_ExecScript(script_file_name, globals())### Apply provided sig file namedefapply_sig_file(database_file_name:str,sig_file_name:str,sig_res_file:str):ifnot os.path.isfile(sig_file_name):print(f"The specified value {sig_file_name} is not a valid file name")return root, extension = os.path.splitext(sig_file_name)if extension !=".sig":print(f"The specified value {sig_file_name} is not a valid sig file")return# Install hook on IDB to collect matches sig_hook =sig_hooks_t() sig_hook.hook()# Start apply process and wait for it ida_funcs.plan_to_apply_idasgn(sig_file_name) ida_auto.auto_wait() matches_no =0for index inrange(0, ida_funcs.get_idasgn_qty()): fname, _, fmatches = ida_funcs.get_idasgn_desc_with_matches(index)if fname in sig_file_name: matches_no = fmatchesbreak matches ={"total_matches": matches_no,"matched_functions": []}for fea in sig_hook.matched_funcs: matches['matched_functions'].append({ "func_name": ida_funcs.get_func_name(fea), "start_ea": hex(fea) })withopen(sig_res_file, 'w')as jsonfile: json.dump(matches, jsonfile, indent=2) print(f"Total matches {matches_no} while applying {sig_file_name} on {database_file_name}, saved results to {sig_res_file}")
### Internal string to bool converter used for command line argumentsdefstr_to_bool(value:str):ifisinstance(value, bool):return valueif value.lower()in{'false','f','0','no','n'}:returnFalseelif value.lower()in{'true','t','1','yes','y'}:returnTrueraiseValueError(f'{value} is not a valid boolean value')# Parse input argumentsparser=argparse.ArgumentParser(description="IDA Python Library Demo")parser.add_argument("-f", "--file", help="File to be analyzed with IDA", type=str, required=True)parser.add_argument("-l", "--list-segments", help="List segmentes", type=str_to_bool, nargs='?', const=True, default=False)
parser.add_argument("-s", "--script-file-name", help="Execute an existing python script file", type=str, required=False)
parser.add_argument("-g", "--sig-file-name", help="Provide a signature file to be applied, requires also -o", type=str, required=False)
parser.add_argument("-o", "--sig-res-file", help="Signature file applying result json file, works only together with -g", type=str, required=False)
parser.add_argument("-p", "--persist-changes", help="Persist database changes", type=str_to_bool, nargs='?', const=True, default=True)
args=parser.parse_args()if (args.sig_file_name is not None and args.sig_res_file is None) or (args.sig_file_name is None and args.sig_res_file is not None):
print("error: '-g/--sig-file-name' and '-o/--sig-res-file' arguments must be specified together or none of them.\n")
parser.print_help()exit(-1)# Run auto analysis on the input fileprint(f"Opening database {args.file}...")idapro.open_database(args.file, True)# Create an undo pointif ida_undo.create_undo_point(b"Initial state, auto analysis"):print(f"Successfully created an undo point...")else:print(f"Failed to created an undo point...")# List segments if required soif args.list_segments:print("Listing segments...")list_segments()# Run a script if one providedif args.script_file_name isnotNone:print(f"Running script {args.script_file_name}...")run_script(script_file_name=args.script_file_name)# Apply signature file if one providedif args.sig_file_name isnotNone:print(f"Applying sig file {args.sig_file_name}...")apply_sig_file(database_file_name=args.file, sig_file_name=args.sig_file_name, sig_res_file=args.sig_res_file)# Revert any changes if specified soifnot args.persist_changes:if ida_undo.perform_undo():print(f"Successfully reverted database changes...")else:print(f"Failed to revert database changes...")# Let the idb in a consistent state, explicitly terminate the databaseprint("Closing database...")idapro.close_database()print("Done, thanks for using IDA!")