Upgrade to Pro — share decks privately, control downloads, hide ads and more …

EXC_BAD_ACCESS in <redacted>. Now what?

EXC_BAD_ACCESS in <redacted>. Now what?

Swizzling your way around proprietary code bugs and crashes.

Avatar for Sash Zats

Sash Zats

July 08, 2015
Tweet

More Decks by Sash Zats

Other Decks in Technology

Transcript

  1. #!/usr/bin/ruby developers_dir = `xcode-select -p`.chomp frameworks_dir = "#{developers_dir}/Platforms/iPhoneSimulator.platform" frameworks_dir +=

    "/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Frameworks/*" swift_frameworks_count = 0 Dir[frameworks_dir].each { |file| framework = "#{file}/#{File.basename(file, ".*")}" next unless File.exist?(framework) puts framework unless `otool -l #{framework} | grep -i swift`.empty? }
  2. if let cls = NSClassFromString("UIPrinterSearchingView") { let block: @objc_block (AspectInfo)

    -> Void = { (aspectInfo) in if let view = aspectInfo.instance() as? UIView { view.frame.size.height = view.superview!.frame.height - 44 } } let blockObject = unsafeBitCast(block, AnyObject.self) cls.aspect_hookSelector( Selector("layoutSubviews"), withOptions: .PositionAfter, usingBlock: blockObject, error: nil ) }
  3. Swizzling 1. Swizzling is still possible in Swift. 2. Set

    applicable OS versions for the patch. 3. Test extensively. On device! 4. Aspect oriented programming.
  4. diffArrays(var_24, eax, edi->_changedItems, nil, nil, nil, nil, nil); void diffArrays(NSArray

    <NSManagedObject *> *arg0, NSArray <NSManagedObject *> *arg1, NSArray <NSManagedObject *> *arg2, NSIndexSet **arg3, NSIndexSet **arg4, NSIndexSet **arg5, NSArray <NSManagedObject *> **arg6, NSIndexSet **arg7);
  5. // Internal structures struct swift_func_wrapper { var trampolinePtr: UnsafeMutablePointer<uintptr_t> var

    functionObject: UnsafeMutablePointer<swift_func_object> } struct swift_func_object { var original_type_ptr: UnsafeMutablePointer<uintptr_t> var unknown: UnsafeMutablePointer<UInt64> var address: uintptr_t var selfPtr: UnsafeMutablePointer<uintptr_t> } // Method we want to call func hello(world: String) -> Void typedef helloFn = (String) -> Void // C function pointer let fn = UnsafeMutablePointer<helloFn>.alloc(1) fn.initialize(hello) let fnWrapper = UnsafeMutablePointer<swift_func_wrapper>(fn) let opaque = COpaquePointer(bitPattern: fnWrapper.memory.functionObject.memory.address) let cFunction = CFunctionPointer<helloFn>(opaque)
  6. // Internal structures struct swift_func_wrapper { var trampolinePtr: UnsafeMutablePointer<uintptr_t> var

    functionObject: UnsafeMutablePointer<swift_func_object> } struct swift_func_object { var original_type_ptr: UnsafeMutablePointer<uintptr_t> var unknown: UnsafeMutablePointer<UInt64> var address: uintptr_t var selfPtr: UnsafeMutablePointer<uintptr_t> }
  7. // Method we want to call func hello(world: String) ->

    Void { print("Hello, \(world)") } typedef helloFn = (String) -> Void
  8. // C function pointer let fn = UnsafeMutablePointer<helloFn>.alloc(1) fn.initialize(hello) let

    fnWrapper = UnsafeMutablePointer<swift_func_wrapper>(fn) let address = fnWrapper.memory.functionObject.memory.address let opaque = COpaquePointer(bitPattern: address) let cFunction = CFunctionPointer<helloFn>(opaque)
  9. C-functions patching · Find the goddamn thing. · Patch implementation.

    · Fishhook - dynamically rebinding symbols in Mach-O binaries. · Call the original implementation maybe?
  10. Conclusions · Objective-C + swizzling = ! · C functions2

    + fishhook = " · Swift + optimization -O = # 2 calling IMP directly from Swift might be possible with @convention syntax
  11. Credits · Perceptual Debugging @kendalldevdiary · Reverse Engineering @Dirk_Gently ·

    Unsafe Swift: For Fun & Profit @xenadu02 · Peter Steinberger's blog by @steipete · All WWDC sessions about debugging by @apple · Aspects by @steipete, fishhook by @facebook