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 methods.

This analysis can be invoked manually at any time with:

  Edit>Other>Objective-C>Reload Objective-C info

Or:

  idaapi.load_and_run_plugin("objc", 1)

You can also disable objc analysis at load time with command line option:

  -Oobjc:+l

Or check the "Lazy mode" option in:

  Edit>Other>Objective-C>Objective-C Options...

Decompilation

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 pseudocode, 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:

  -Oobjc:-h

Or uncheck the "Enable decompiler plugin for Objective-C" option in:

  Edit>Other>Objective-C>Objective-C Options...

Debugging

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:

  -Oobjc:-s

Or by unchecking the "Enable SIP for Objective-C" option in:

  Edit>Other>Objective-C>Objective-C Options...

Step Into Message

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:

  Shift+O

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, 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.

NSConcreteStackBlock

The objc plugin can also be used to analyze Apple 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:

  Ctrl+Shift+S

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 pseudocode 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.

NSConcreteGlobalBlock

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

Or:

  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

Last updated