How to select architecture using idalib?

I want to analysis a Universal macOS Binary, it’s include a multi-arch binary (x64 & ARM), and when I use idalib in python, it’s cannot be select arch manually.

e.g.

import idapro
# copy /System/Applications/Books.app/Contents/MacOS/Books to ./Books
idapro.open_database("./Books", run_auto_analysis=True)
idaapi.auto_wait()
# do something here
idapro.close_database(save=False)

I believe for 9.0 you’ll have to pre-process the binary with lipo to extract the necessary slice. In 9.1 we’ll add a possibility to pass IDA-compatible command-line arguments to open_database(), so you’ll be able to specify -parm or -ppc, which should influence the default slice selection.

2 Likes

Thank you for your quick response!

Hi, when I use -TFat Mach-O File, 2:

idapro.open_database("./Books", True, '-TFat Mach-O File, 2')

an error occurs:

Unknown switch '-T' -> OK

idalib’s args seems not same with ida/idat?

Above response says to use -p, not -T?

-p means processor type (e.g. -parm:armv7a), I think it’s not solution to select File Format :face_with_monocle:

it’s a official image:

Actually, -p should help with fat Mach-O because the loader pre-selects the slice matching the current processor.

as you say, if I set args -parm, idalib seems not correctly to analysis. Additionally, we can see log message:

Format 'Fat Mach-O file, 1. X86_64 (metapc)' is not compatible with the selected processor ('arm'), disassembly might be erroneous

Thanks for checking. It seems we still have some things to fix…

Hi, has any update on this issue?

Hi, AFAIK -T should be supported starting 9.1 (and in any case, in 9.2).

Yes, but in my test case it’s seems cannot works…

#!/usr/bin/env python3
"""
Database exploration example for IDA Domain API.

This example demonstrates how to open an IDA database and explore its basic properties.
"""

import argparse
from dataclasses import asdict

import ida_domain
from ida_domain import Database
from ida_domain.database import IdaCommandOptions


def explore_database(db_path):
    """Explore basic database information."""
    ida_options = IdaCommandOptions(auto_analysis=True, new_database=True, file_type='Fat Mach-O file, 2')
    with Database.open(db_path, ida_options) as db:
        # Get basic information
        print(f'Address range: {hex(db.minimum_ea)} - {hex(db.maximum_ea)}')
    
        # Get metadata
        print('Database metadata:')
        metadata_dict = asdict(db.metadata)
        for key, value in metadata_dict.items():
            print(f'  {key}: {value}')

        # Count functions
        function_count = 0
        for _ in db.functions:
            function_count += 1
        print(f'Total functions: {function_count}')


def main():
    """Main entry point with argument parsing."""
    parser = argparse.ArgumentParser(description='Database exploration example')
    parser.add_argument(
        '-f', '--input-file', help='Binary input file to be loaded', type=str, required=True
    )
    args = parser.parse_args()
    explore_database(args.input_file)


if __name__ == '__main__':
    from dotenv import load_dotenv
    load_dotenv()
    main()

a minimal PoC:

    import idapro
    import idaapi
    
    idapro.open_database('/System/Applications/Books.app/Contents/MacOS/Books', run_auto_analysis=True, args="-TFat Mach-O file, 2")
    idaapi.auto_wait()
    idapro.close_database(save=False)

I can’t test it right now, but I wonder if it’s a problem of the space in the format name. Maybe try like this:

args='-T"Fat Mach-O file, 2"'

still cannot works :frowning:

It’s confusing to me, it’s works well when I use command line:

/Applications/IDA\ Professional\ 9.2.app/Contents/MacOS/ida "-TFat Mach-O File, 2" '/System/Applications/Books.app/Contents/MacOS/Books'

it seems apostrophes work:

idapro.open_database(‘/System/Applications/Books.app/Contents/MacOS/Books’, run_auto_analysis=True, args=“‘-TFat Mach-O file, 2’ -ot.i64”)

I added -o because the original location is not writeable.

it’s cannot works for me…

here my test case

import idapro
import idaapi

idapro.open_database('/System/Applications/Books.app/Contents/MacOS/Books', run_auto_analysis=True, args="'-TFat Mach-O file, 2' -oa.i64")
idaapi.auto_wait()
idapro.close_database(save=False)

there is no output in terminal…

but it’s works well if I remove `-T`.

to see analysis messages you need to call idapro.enable_console_messages(True), and/or add -Llogfile.txt to the commandline options to copy them to a file.

import idapro
import idaapi

idapro.enable_console_messages(True)
idapro.open_database('/System/Applications/Books.app/Contents/MacOS/Books', run_auto_analysis=True, args='"-TFat Mach-O file, 2" -oa.i64')

idaapi.auto_wait()
idapro.close_database(save=False)
Possible file format: Fat Mach-O file, 1. X86_64 (/Applications/IDA Professional 9.1.app/Contents/MacOS/loaders/macho.dylib)
Possible file format: Fat Mach-O file, 2. ARM64 (/Applications/IDA Professional 9.1.app/Contents/MacOS/loaders/macho.dylib)

  bytes   pages size description
--------- ----- ---- --------------------------------------------
  1327104   162 8192 allocating memory for b-tree...
  1327104   162 8192 allocating memory for virtual array...
   262144    32 8192 allocating memory for name pointers...
-----------------------------------------------------------------
  2916352            total memory allocated

Unknown switch '-T' -> OK

it’s seems cannot process `-T`

and moreever, I cannot use idapro in 9.2:

import os
os.environ['IDADIR'] = '/Applications/IDA Professional 9.2.app/Contents/MacOS'

import idapro
import idaapi

log:

Import failed: dlopen(/Applications/IDA Professional 9.2.app/Contents/MacOS/python/lib-dynload/_ida_pro.so, 0x0002): symbol not found in flat namespace '_bitcountr_zero'. Current sys.path:
        /Applications/IDA Professional 9.2.app/Contents/MacOS/python
        /Applications/IDA Professional 9.2.app/Contents/MacOS/python/lib-dynload
        ...
        /Applications/IDA Professional 9.2.app/Contents/MacOS/python
Traceback (most recent call last):
  File "xxx", line 5, in <module>
    import idapro
  File "xxx/.venv/lib/python3.12/site-packages/idapro/__init__.py", line 75, in <module>
    raise ImportError(f"Failed to initialize IDA library, {error_description}, check logging for additional information\n")
ImportError: Failed to initialize IDA library, exception <_FuncPtr object at 0x100605a90> returned a result with an exception set, check logging for additional information

it’s works when I use ida python (/opt/homebrew/Cellar/python@3.13/3.13.5/Frameworks/Python.framework/Versions/3.13/bin/python)

$ /Applications/IDA\ Professional\ 9.2.app/Contents/MacOS/idapyswitch
The following Python installations were found:
    #0: 3.13.0 ('') (/opt/homebrew/Cellar/python@3.13/3.13.5/Frameworks/Python.framework/Versions/3.13/Python)
    #1: 3.12.0 ('') (/opt/homebrew/Cellar/python@3.12/3.12.7_1/Frameworks/Python.framework/Versions/3.12/Python)
    #2: 3.9.0 ('') (/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/Python3)
    #3: 3.9.0 ('') (/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/Python3)
Please pick a number between 0 and 3 (default: 0) 
$ /opt/homebrew/Cellar/python@3.13/3.13.5/Frameworks/Python.framework/Versions/3.13/bin/python3 test.py
...
OBJC: Identified Objective-C runtime version >= 2.0
Auto analysis completed
ida_ida.inf_get_procname()='ARM'
...
import os
import sys
os.environ['IDADIR'] = '/Applications/IDA Professional 9.2.app/Contents/MacOS'

sys.path.append(os.path.join(os.environ['IDADIR'], 'python'))
sys.path.append(os.path.join(os.environ['IDADIR'], 'idalib/python'))

import idapro
import idaapi
import ida_ida

idapro.enable_console_messages(True)
idapro.open_database('/Users/mason/Downloads/osinstallersetupd', run_auto_analysis=True, args='"-TFat Mach-O file, 2"')
print(f'{ida_ida.inf_get_procname()=}')
idaapi.auto_wait()
idapro.close_database(save=False)

but it’s cannot works for any version for normal python

$ uv venv --python 3.13
...
$ source .venv/bin/activate
$ python test.py
Import failed: dlopen(/Applications/IDA Professional 9.2.app/Contents/MacOS/python/lib-dynload/_ida_pro.so, 0x0002): symbol not found in flat namespace '_bitcountr_zero'. Current sys.path:
        /Applications/IDA Professional 9.2.app/Contents/MacOS/python
        /Applications/IDA Professional 9.2.app/Contents/MacOS/python/lib-dynload
        ...
        /Applications/IDA Professional 9.2.app/Contents/MacOS/python
Traceback (most recent call last):
  File "/Applications/IDA Professional 9.2.app/Contents/MacOS/python/init.py", line 53, in <module>
    globals()[f"ida_{mod}"] = __import__(f"ida_{mod}")
                              ~~~~~~~~~~^^^^^^^^^^^^^^
  File "/Applications/IDA Professional 9.2.app/Contents/MacOS/python/ida_hexrays.py", line 105, in <module>
    import ida_pro
  File "/Applications/IDA Professional 9.2.app/Contents/MacOS/python/ida_pro.py", line 20, in <module>
    import _ida_pro
ImportError: dlopen(/Applications/IDA Professional 9.2.app/Contents/MacOS/python/lib-dynload/_ida_pro.so, 0x0002): symbol not found in flat namespace '_bitcountr_zero'

Traceback (most recent call last):
  File "test.py", line 10, in <module>
    import idaapi
  File "/Applications/IDA Professional 9.2.app/Contents/MacOS/python/idaapi.py", line 5, in <module>
    from ida_hexrays import *
  File "/Applications/IDA Professional 9.2.app/Contents/MacOS/python/ida_hexrays.py", line 105, in <module>
    import ida_pro
  File "/Applications/IDA Professional 9.2.app/Contents/MacOS/python/ida_pro.py", line 20, in <module>
    import _ida_pro
ImportError: dlopen(/Applications/IDA Professional 9.2.app/Contents/MacOS/python/lib-dynload/_ida_pro.so, 0x0002): symbol not found in flat namespace '_bitcountr_zero'