binaryninja-api icon indicating copy to clipboard operation
binaryninja-api copied to clipboard

Support for iOS 18 Objective-C Optimizations in dyld_shared_cache

Open WeiN76LQh opened this issue 1 year ago • 2 comments

Version and Platform (required):

  • Binary Ninja Version: 4.2.6304-dev (65f49c87)
  • OS: macOS
  • OS Version: 15.0
  • CPU Architecture: M1

Bug Description: Sometimes loading a certain image from DSC results in Binary Ninja getting caught in what appears to be an infinite loop (probably finite bound to a very large number). During this time BN prints the following to the log view:

[SharedCache.ObjC] Failed to process an ivar at offset 0x180ded9a8

The address value at the end is an example. This line will keep being printed over and over, and the address value will increment by 0x20 each time. I'm guessing there's something wrong with the metadata parsing causing it to think there's a huge number of ivars to process.

Steps To Reproduce:

  1. Open a copy of DSC extracted from an iOS 18.0 beta 4 ipsw (22A5316j) for an iPhone 15 Pro Max (iPhone16,2) in Binary Ninja
  2. Wait for the initial analysis to complete
  3. Load the image /System/Library/Frameworks/Contacts.framework/Contacts

Binary: Extract the DSC from an iOS 18.0 beta 4 ipsw (22A5316j) for an iPhone 15 Pro Max (iPhone16,2). This has been a problem with other copies of DSC and other images within DSC, this is just one I know to be problematic with the contacts framework.

Additional Information: I believe this is a back trace for the thread thats doing the Objective-C metadata parsing. Hopefully its helpful without symbols given the version and platform information above.

* thread #39, name = 'Worker PRI '
  * frame #0: 0x000000018b2116dc dyld`invocation function for block in dyld3::MachOFile::forEachSegment(void (dyld3::MachOFile::SegmentInfo const&, bool&) block_pointer) const + 40
    frame #1: 0x000000018b1c42dc dyld`dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const + 300
    frame #2: 0x000000018b211688 dyld`dyld3::MachOFile::forEachSegment(void (dyld3::MachOFile::SegmentInfo const&, bool&) block_pointer) const + 172
    frame #3: 0x000000018b1e4e90 dyld`dyld4::JustInTimeLoader::contains(dyld4::RuntimeState&, void const*, void const**, unsigned long long*, unsigned char*) const + 260
    frame #4: 0x000000018b1f6fa4 dyld`invocation function for block in dyld4::APIs::findImageMappedAt(void const*, dyld3::MachOLoaded const**, bool*, char const**, void const**, unsigned long long*, unsigned char*, dyld4::Loader const**) + 144
    frame #5: 0x000000018b1d0404 dyld`dyld4::RuntimeLocks::withLoadersReadLock(void () block_pointer) + 100
    frame #6: 0x000000018b1f6da4 dyld`dyld4::APIs::findImageMappedAt(void const*, dyld3::MachOLoaded const**, bool*, char const**, void const**, unsigned long long*, unsigned char*, dyld4::Loader const**) + 756
    frame #7: 0x000000018b1fa6a4 dyld`dyld4::APIs::_dyld_find_unwind_sections(void*, dyld_unwind_sections*) + 124
    frame #8: 0x0000000198f7ddf0 libunwind.dylib`libunwind::UnwindCursor<libunwind::LocalAddressSpace, libunwind::Registers_arm64>::setInfoBasedOnIPRegister(bool) + 140
    frame #9: 0x0000000198f82288 libunwind.dylib`unw_set_reg + 636
    frame #10: 0x000000018b50436c libc++abi.dylib`__gxx_personality_v0 + 384
    frame #11: 0x0000000198f83080 libunwind.dylib`unwind_phase2 + 596
    frame #12: 0x0000000198f82e14 libunwind.dylib`_Unwind_RaiseException + 804
    frame #13: 0x000000018b503c7c libc++abi.dylib`__cxa_throw + 84
    frame #14: 0x000000011df0f6e4 libsharedcache.dylib`___lldb_unnamed_symbol3202 + 412
    frame #15: 0x000000011deb4d58 libsharedcache.dylib`___lldb_unnamed_symbol2785 + 424
    frame #16: 0x000000011deb2a5c libsharedcache.dylib`___lldb_unnamed_symbol2782 + 2312
    frame #17: 0x000000011dec5e14 libsharedcache.dylib`___lldb_unnamed_symbol2801 + 33316
    frame #18: 0x000000011deeafbc libsharedcache.dylib`___lldb_unnamed_symbol2952 + 4844
    frame #19: 0x000000011def8814 libsharedcache.dylib`BNDSCViewLoadImageWithInstallName + 168
    frame #20: 0x0000000310098070 libsharedcacheui.dylib`___lldb_unnamed_symbol3814 + 48
    frame #21: 0x00000003100aeb64 libsharedcacheui.dylib`___lldb_unnamed_symbol4472 + 36
    frame #22: 0x00000001156af22c libbinaryninjacore.1.dylib`___lldb_unnamed_symbol29525 + 2160
    frame #23: 0x00000001156ae6e4 libbinaryninjacore.1.dylib`___lldb_unnamed_symbol29520 + 12
    frame #24: 0x000000018b54b2e4 libsystem_pthread.dylib`_pthread_start + 136

WeiN76LQh avatar Oct 29 '24 00:10 WeiN76LQh

Resolved in dev builds >= 4.2.6359

This is 100% an iOS 18 cache issue (which we do not fully support yet) however I've added a sanity check for ivars so it should hopefully not get stuck in this anymore.

0cyn avatar Nov 05 '24 14:11 0cyn

Leaving this open to track iOS 18 support for new objective-c optimizations

0cyn avatar Nov 05 '24 15:11 0cyn

libWebKitSwift.dylib.zip

Version and Platform (required):

Binary Ninja Version: 5.3.8760-dev (fba98d3c) OS: macOS OS Version: Tahoe 26.1 CPU Architecture: M4 Max

Similar behavior found in a webkit dylib for macOS (macho.objc error instead of the reported SharedCache.ObjC error)

[16288423728428423870:2812132435300266560 macho.objc error] Failed to process an ivar at offset 0x2fb06e0

loganleland avatar Dec 11 '25 18:12 loganleland

@loganleland Can you please file a new issue? Your problem appears to be related to how relocations are handled in Mach-O files rather than anything specific to Objective-C changes in iOS 18.

bdash avatar Dec 11 '25 21:12 bdash

@loganleland Can you please file a new issue? Your problem appears to be related to how relocations are handled in Mach-O files rather than anything specific to Objective-C changes in iOS 18.

Opened a new issue here: https://github.com/Vector35/binaryninja-api/issues/7781

loganleland avatar Dec 12 '25 00:12 loganleland