Objective-C Analysis Plugin

The objc plugin performs Objective-C specific analysis on the database.

For an overview of what the plugin can do, see the menu options in Edit>Other>Objective-C, or the config options in objc.cfg.

  Type Information
    The bulk of the plugin's work is done at file load time, when it will parse all
    Objective-C type information embedded in the binary, and use this to create
    tinfo_t structures for all known classes and construct prototypes for all known
    This analysis can be invoked manually at any time with:
      Edit>Other>Objective-C>Re-load Objective-C info
      idaapi.load_and_run_plugin("objc", 1)
    You can also disable objc analysis at load time with command line option:
    Or check the "Lazy mode" option in:
      Edit>Other>Objective-C>Objective-C Options...

    The plugin will also perform Objective-C analysis during decompilation.
    When a function is decompiled, the plugin will analyze any calls to objc_msgSend,
    and use the arguments to determine if objc_msgSend will ultimately invoke one of
    the methods in the current database.
    If such a situation is detected, the plugin will replace the call to objc_msgSend with
    a call to the target method, and add an xref to the method. This is done in the hopes that
    continued use of the decompiler will improve call graphs for Objective-C binaries.
    If the target method has type information, then the return type can be used to refine
    the types of local variables in the psuedocode, which in turn could lead to more method
    calls being detected, and so on.
    You can disable objc analysis in the pseudocode with command line option:
    Or uncheck the "Enable decompiler plugin for Objective-C" option in:
      Edit>Other>Objective-C>Objective-C Options...

    objc also provides tools for dynamic analysis.
    During debugging, you can analyze objc info for a specific library
    by right-clicking in the Modules window and selecting "Load debug info".
    This operation can also be performed programmatically with:
      n = idaapi.netnode()
      n.create("$ objc")
      n.supset(1, "/module/path", 'R')
      idaapi.load_and_run_plugin("objc", 3)
    If you prefer that objc does not perform analysis during "Load debug info",
    (say if DWARF information is available for a module and you prefer that),
    you can disable this functionality with command line option:
    Or by unchecking the "Enable SIP for Objective-C" option in:
      Edit>Other>Objective-C>Objective-C Options...

  Step Into
    The plugin also implements a "step into" debugger action for Objective-C.
    If you use this action before a call to objc_msgSend, objc will try to calculate
    the address of method that is being invoked, and break at the method address
    rather than step into the objc_msgSend function itself.
    You can perform this action with shortcut:
    Or via the menu option:
      Debugger>Run until message received
    Or programmatically with:
      idaapi.load_and_run_plugin("objc", 2)
    This action can be very useful, but you must be careful. When invoked, the action
    will automatically run to the address of objc_msgSend, analyze its arguments,
    then continue to the target method.
    If there is no subsequent call to objc_msgSend in the program, then you will lose
    control of the process. It is best to use this action only when you are sure that
    IP is in the vicinity of an objc_msgSend call.

    The objc plugin can also be used to analyze binaries that make heavy
    use of blocks (https://clang.llvm.org/docs/Block-ABI-Apple.html).
    The analysis involves identifying NSConcreteStackBlock instances on the stack,
    and creating a specialized Block_layout structure to apply to the function's
    stack frame.
    The end result transforms the following sequence of statements:
    loc_BF60:                               Block_layout_BF60 v1;
      v1 = _NSConcreteStackBlock;           v1.isa        = _NSConcreteStackBlock;
      v2 = 0x...;                           v1.flags      = 0x...;
      v3 = 0;                               v1.reserved   = 0;
      v4 = __block_invoke;            =>    v1.invoke     = __block_invoke;
      v5 = &__block_descriptor_tmp;         v1.descriptor = &__block_descriptor_tmp;
      v6 = ...                              v1.lvar1      = ...
      v7 = ...                              v1.lvar2      = ...
      ...                                   ...
      func(&v1);                            func(&v1);
    Already this cleans up the analysis quite a lot, but more importantly this new
    Block_layout_BF60 structure will be applied to the prototype of __block_invoke,
    which can heavily improve the pseudocode.
    Block analysis can be performed on the database with:
      Edit>Other>Objective-C>Analyze stack-allocated blocks (entire database)
    Or programmatically with:
      idaapi.load_and_run_plugin("objc", 5)
    You can also perform block analysis on a specific function:
      Edit>Other>Objective-C>Analyze stack-allocated blocks (current function)
    Or with shortcut:
    Or programmatically:
      n = idaapi.netnode()
      n.create("$ objc")
      n.altset(1, 0xBF60, 'R') # the address can be any address within the function
      idaapi.load_and_run_plugin("objc", 5)
    These actions work in both the Disassembly and Psueudocode windows,
    but note that you must refresh the pseudocode with F5 for the changes
    to take full effect.
    Also, please note that this feature makes use of the microcode in the hexrays SDK,
    so you must have the decompiler in order to use it.

    Global blocks (i.e. blocks that don't make use of local variables) are much easier
    to analyze, and simply involve identifying references to NSConcreteGlobalBlock in
    the __const segment.
    Global blocks are analyzed automatically at load time, but the analysis
    can be performed manually at any time with:
      Edit>Other>Objective-C>Re-analyze global block functions
      idaapi.load_and_run_plugin("objc", 4)

  Command Line
    Here's a summary of the command-line arguments that can be passed to objc:
    objc features can be enabled or disabled using '+' or '-', followed by one of the following characters:
      v: verbose mode
      s: source info provider
      h: hexrays decompiler analysis
      l: lazy mode
    For example, -Oobjc:+v:+l:-s will enable verbose and lazy mode, and will disable the objc SIP.

See also Debugger for Intel Mac OS X Remote iOS debugger DYLD Shared Cache Utils
Index | Previous topic | Next topic