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.

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