## Keyboard shortcuts

Press `←` or `→` to navigate between chapters

Press `S` or `/` to search in the book

Press `?` to show this help

Press `Esc` to hide this help

# idalib

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

1. Navigate to the `idalib/python` folder within the IDA Pro installation directory
2. Run the command: `pip install .`

{% hint style=“info” %} 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. {% endhint %}

## Setting up the ida library Python module

Run the Activation Script

1. 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):

       python /path/to/IDA/installation/py-activate-idalib.py [-d /path/to/active/IDA/installation]

   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

1. 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 python3
    import argparse
    import os
    import json
    import idapro
    from pathlib import Path
    import ida_segment
    import ida_idaapi
    import ida_funcs
    import ida_idp
    import ida_auto
    import ida_undo

    class sig_hooks_t(ida_idp.IDB_Hooks):

        def __init__(self):
            ida_idp.IDB_Hooks.__init__(self)
            self.matched_funcs = set()

        def func_added(self, pfn):
            self.matched_funcs.add(pfn.start_ea)

        def func_deleted(self, func_ea):
            try:
                self.matched_funcs.remove(func_ea)
            except:
                pass

        def func_updated(self, pfn):
            self.matched_funcs.add(pfn.start_ea)

        def idasgn_loaded(self, sig_name):
            return print(f"Sig {sig_name} loaded")

        def dump_matches(self):
            for fea in self.matched_funcs:
                print(f"Matched function {ida_funcs.get_func_name(fea)}")

    ### List the segments for the loaded binary
    def list_segments():
        nb_items = ida_segment.get_segm_qty()
        print("Segments number:",  nb_items)
        for i in range(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 script
    def run_script(script_file_name:str):
        if not 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 name
    def apply_sig_file(database_file_name:str, sig_file_name:str, sig_res_file:str):
        if not 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 = 0
        for index in range(0, ida_funcs.get_idasgn_qty()):
            fname, _, fmatches = ida_funcs.get_idasgn_desc_with_matches(index)
            if fname in sig_file_name:
                matches_no = fmatches
                break

        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) })

        with open(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 arguments
    def str_to_bool(value:str):
        if isinstance(value, bool):
            return value
        if value.lower() in {'false', 'f', '0', 'no', 'n'}:
            return False
        elif value.lower() in {'true', 't', '1', 'yes', 'y'}:
            return True
        raise ValueError(f'{value} is not a valid boolean value')

    # Parse input arguments
    parser=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 file
    print(f"Opening database {args.file}...")
    idapro.open_database(args.file, True)

    # Create an undo point
    if 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 so
    if args.list_segments:
        print("Listing segments...")
        list_segments()

    # Run a script if one provided
    if args.script_file_name is not None:
        print(f"Running script {args.script_file_name}...")
        run_script(script_file_name=args.script_file_name)

    # Apply signature file if one provided
    if args.sig_file_name is not None:
        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 so
    if not 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 database
    print("Closing database...")
    idapro.close_database()
    print("Done, thanks for using IDA!")