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

Hacking Marzipan

Hacking Marzipan

I will show the hacks currently needed to try Apple's new iOSMac platform, codenamed "Marzipan", and walk through what I needed to do to get PDF Viewer to run on macOS Mojave. Learn about the history, the current status, the timeline, and how to port your app today.

Video: https://www.youtube.com/watch?v=2OuQarA0a7I
Blog Post: https://pspdfkit.com/blog/2018/porting-ios-apps-to-mac-marzipan-iosmac-uikit-appkit/

This talk was presented at try! Swift New York on Sept 5, 2018.

PDF Viewer: https://pdfviewer.io
@steipete: https://twitter.com/steipete
marzipanify: https://github.com/steventroughtonsmith/marzipanify
MarzipanPlatter: https://github.com/biscuitehh/MarzipanPlatter
iOSMacToolbarController.swift: https://gist.github.com/steipete/b8bf675028ee476a9ca9af1ff14ff1e0
iOS Mac Internals: https://kirb.me/2018/06/07/iosmac-research.html
Marzipan Article on 9To5Mac: https://9to5mac.com/2018/06/13/marzipan-in-mojave-porting-ios-apps-to-macos/
First PDF Viewer port: https://twitter.com/steipete/status/1006292370160316418
marzipan_hook: https://github.com/justMaku/marzipan_hook
Marzipan Internals + Reveal: https://www.youtube.com/watch?v=EpUnke2yDug

Marzipan+React Native 🙀: https://github.com/notjosh/Marzipants

Avatar for Peter Steinberger

Peter Steinberger

September 05, 2018
Tweet

More Decks by Peter Steinberger

Other Decks in Technology

Transcript

  1. Some History This has been done before... Peter Steinberger -

    @steipete - Hacking Marzipan - try! Swift NYC 2018
  2. Timeline » Dec 20, 2017: Leak: Mark Gurman/Bloombergleak » Jun

    4-8, 2018: WWDC 2018: Sneek Peek » Jun 7: MarzipanPlatter (Michael Thomas) » Jun 17: marzipanify (Steven Troughton-Smith) » Jul 3: Largest change, Mojave Beta 3 » Sept/Oct: Mojave GM leak bloomberg.com/news/articles/2017-12-20/apple-is-said-to-have-plan-to-combine-iphone-ipad-and-mac-apps Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  3. Fun Facts » Scale Factor is at 0.77 » Either

    UIKit or AppKit, can't mix » Marzipandemic: The spread of single-window odd-UI originally-on-iOS apps to the Mac » Some UI paradigms can be weird... Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  4. Why look at this now? Peter Steinberger - @steipete -

    Hacking Marzipan - try! Swift NYC 2018
  5. iOSMac Architecture otool -L /Applications/VoiceMemos.app/Contents/MacOS/VoiceMemos /Applications/VoiceMemos.app/Contents/MacOS/VoiceMemos: /System/Library/Frameworks/Accounts.framework/Versions/A/Accounts /System/Library/PrivateFrameworks/AppleAccount.framework/Versions/A/AppleAccount /System/Library/Frameworks/CoreSpotlight.framework/Versions/A/CoreSpotlight /System/Library/Frameworks/CoreData.framework/Versions/A/CoreData

    /System/Library/Frameworks/CloudKit.framework/Versions/A/CloudKit /System/Library/PrivateFrameworks/AppSupport.framework/Versions/A/AppSupport /System/Library/Frameworks/AVFoundation.framework/Versions/A/AVFoundation /System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics /System/Library/Frameworks/CoreMedia.framework/Versions/A/CoreMedia /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation /System/Library/PrivateFrameworks/FrontBoardServices.framework/Versions/A/FrontBoardServices /System/Library/PrivateFrameworks/MediaRemote.framework/Versions/A/MediaRemote /System/Library/PrivateFrameworks/MediaServices.framework/Versions/A/MediaServices /System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore /System/Library/PrivateFrameworks/TCC.framework/Versions/A/TCC /System/iOSSupport/System/Library/Frameworks/UIKit.framework/Versions/A/UIKit /System/iOSSupport/System/Library/PrivateFrameworks/VoiceMemos.framework/Versions/A/VoiceMemos /usr/lib/libobjc.A.dylib /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  6. Processes » VoiceMemos.app /Applications/VoiceMemos.app » voicememod /System/iOSSupport/System/Library/ PrivateFrameworks/VoiceMemos.framework/Support/ voicememod »

    UIKitSystem.app /System/Library/CoreServices/ UIKitSystem.app » UIKitHostApp.xpc (disguised) /System/Library/ PrivateFrameworks/UIKitHostAppServices.framework/ Versions/A/XPCServices/UIKitHostApp.xpc
  7. UIKitSystem $ ./System/Library/CoreServices/UIKitSystem.app/Contents/MacOS/UIKitSystem UIKitSystemApp is the system app for iosmac

    applications. It cannot be started directly. Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  8. UIKitSystem Frameworks $ otool -L /System/Library/CoreServices/UIKitSystem.app/Contents/MacOS/UIKitSystem /System/Library/CoreServices/UIKitSystem.app/Contents/MacOS/UIKitSystem: /System/Library/PrivateFrameworks/AssertionServices.framework/Versions/A/AssertionServices /usr/lib/libAccessibility.dylib /System/Library/CoreServices/UIKitSystem.app/Contents/Frameworks/UIKitSystemAppCore.framework/...

    /System/iOSSupport/System/Library/Frameworks/UIKit.framework/Versions/A/UIKit /System/Library/PrivateFrameworks/BackBoardServices.framework/Versions/A/BackBoardServices /System/iOSSupport/System/Library/PrivateFrameworks/UIKitServices.framework/Versions/A/UIKitServices /System/Library/PrivateFrameworks/UIKitSystemAppServices.framework/Versions/A/UIKitSystemAppServices /System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore /System/Library/PrivateFrameworks/BaseBoard.framework/Versions/A/BaseBoard /System/Library/PrivateFrameworks/FrontBoardServices.framework/Versions/A/FrontBoardServices /System/iOSSupport/System/Library/PrivateFrameworks/FrontBoard.framework/Versions/A/FrontBoard /System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation /usr/lib/libobjc.A.dylib /usr/lib/libSystem.B.dylib /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation /System/Library/PrivateFrameworks/Swift/libswift(...).dylib Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  9. UIKitSystem Entitlements $ ldid -e /System/Library/PrivateFrameworks/UIKitHostAppServices.framework/Versions /A/XPCServices/UIKitHostApp.xpc/Contents/MacOS/UIKitHostApp - applicationservices.allowedtowrapanotherprocess -

    com.apple.private.defaults-impersonate - com.apple.uikitsystemapp.bundlehost - com.apple.uikitsystemapp.client Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  10. DISCLAIMER » Things will break » Release Marzipan apps is

    tricky » Make backups, use a separate Mac if possible » Disabling security is a bad idea » I have no idea what I'm doing either Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  11. Prepare MacBook for Hackery == Disable Security ! sudo csrutil

    disable sudo nvram boot-args=“amfi_get_out_of_my_way=0x1”1 <key>com.apple.private.iosmac</key> <true/> 1 https://www.theiphonewiki.com/wiki/AppleMobileFileIntegrity Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  12. Virtual Machines do not work Peter Steinberger - @steipete -

    Hacking Marzipan - try! Swift NYC 2018
  13. CAUTION FAST SLIDES AHEAD I did really dumb things and

    you shouldn't look to closely Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  14. @interface UILabel (PSPDFMarzipan) // Otherwise we get an unrecognized selector

    - (NSUInteger)ns_widgetType; @end @implementation UILabel (PSPDFMarzipan) - (NSUInteger)ns_widgetType { return 0; } @end @interface UITextField (PSPDFMarzipan) // Otherwise we get an unrecognized selector - (NSUInteger)ns_widgetType; @end @implementation UITextField (PSPDFMarzipan) - (NSUInteger)ns_widgetType { return 0; } @end Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  15. @interface UILabel (PSPDFMarzipan) // Otherwise we get an unrecognized selector

    - (NSUInteger)ns_widgetType; @end @implementation UILabel (PSPDFMarzipan) - (NSUInteger)ns_widgetType { return 1; } @end Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  16. UIStackView system spacing - (void)setPspdf_fallbackSpacing:(CGFloat)fallbackSpacing { if (@available(iOS 11.0, *))

    { self.spacing = UIStackViewSpacingUseSystem; } else { self.spacing = fallbackSpacing; } } Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  17. UIStackView system spacing yolo - (void)setPspdf_fallbackSpacing:(CGFloat)fallbackSpacing { //if (@available(iOS 11.0,

    *)) { // self.spacing = UIStackViewSpacingUseSystem; //} else { self.spacing = fallbackSpacing; //} } Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  18. Lesson: Do not mix UIKit and AppKit Peter Steinberger -

    @steipete - Hacking Marzipan - try! Swift NYC 2018
  19. Taking over VoiceMemos Compile Hook.dylib replace("\x32\x00\x00\x00\x20\x00\x00\x00\x01\x00\x00\x00", "\x32\x00\x00\x00\x20\x00\x00\x00\x06\x00\x00\x00") DYLD_INSERT_LIBRARIES=Hook.dylib /Applications/VoiceMemos.app/Contents/MacOS/VoiceMemos &

    + (void)load { Class originalClass = NSClassFromString(@"RecorderAppDelegate"); Method originalMeth = class_getInstanceMethod(originalClass, @selector(applicationDidFinishLaunching:)); sOriginalImp = method_getImplementation(originalMeth); Method replMeth = class_getInstanceMethod(NSClassFromString(@"Hook"), @selector(applicationDidFinishLaunching:)); method_exchangeImplementations(originalMeth, replMeth); } - (void)applicationDidFinishLaunching:(id)sender { UIViewController *vc = [[UIViewController alloc] init]; [vc setTitle:@"hello wwwdc"]; UIWindow *window = [[UIWindow alloc] init]; [window setValue:vc forKey:@"rootViewController"]; [window makeKeyAndVisible]; } Michał Kałużny, https://github.com/justMaku/marzipan_hook
  20. Adds a few methods to runtime "Marzipan Glue" @implementation NSBundle

    (Marzipan) + (NSString *)currentStringsTableName { return nil; } @end @implementation NSObject (Marzipan) - (CGFloat)_bodyLeading { return 0.0; } @end Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  21. Patches Info.plist let infoPlist = [NSMutableDictionary dictionaryWithContentsOfFile:infoPlistPath]; infoPlist[@"LSRequiresIPhoneOS"] = @NO;

    infoPlist[@"CFBundleSupportedPlatforms"] = @[@"MacOSX"]; infoPlist[@"MinimumOSVersion"] = @"10.14"; infoPlist[@"CanInheritApplicationStateFromOtherProcesses"] = @YES; infoPlist[@"UIUserInterfaceStyle"] = @"Automatic"; [infoPlist removeObjectForKey:@"DTSDKName"]; // Also: DTSDKBuild, DTCompiler, DTPlatformBuild, // DTPlatformVersion, DTXcode, DTXcodeBuild, DTPlatformName if (INJECT_MARZIPAN_GLUE) { infoPlist[@"LSEnvironment"] = @{ @"DYLD_INSERT_LIBRARIES": @"@executable_path/../Frameworks/MarzipanGlue.dylib" }; } [infoPlist writeToFile:infoPlistPath atomically:NO]; Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  22. Modifies Mach Header struct build_version_command ucmd = *(struct build_version_command*)imageHeaderPtr; ucmd.platform

    = PLATFORM_IOSMAC; ucmd.minos = 12<<16|0<<8|0; ucmd.sdk = 10<<16|14<<8|0; Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  23. Adds Entitlements entitlementsDict[@"com.apple.private.iosmac"] = @YES; let resignCommand = [NSString stringWithFormat:@"/usr/bin/codesign

    --force --sign - --entitlements \"%@\" --timestamp=none \"%@\" &> /dev/null", entitlementsPath, appBundlePath]; Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  24. Step 1 iOS 12 as Minimum Deployment Target LC_BUILD_VERSION vs

    LC_BUILD_VERSION_MIN_MACOS Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  25. Step 2: Remove Features! » UIWebView (already deprecated, so get

    rid of it) » SFSafariViewController (not yet there) » CTTelephonyNetworkInfo » SLComposeViewController » MFMailComposeViewController » OpenGLES (Metal or bust) » AddressBook Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  26. Not all symbols are there ./MarzipanPlatter-iOS dyld: Symbol not found:

    _OBJC_CLASS_$_UIMarkupTextPrintFormatter Referenced from: /Users/steipete/Projects/HackingMarzipan/marzipanify/PDFViewer.app/ Contents/MacOS/./PDFViewer (which was built for Mac OS X 12.0) Expected in: /System/iOSSupport/System/Library/Frameworks/UIKit.framework/UIKit in /Users/steipete/Projects/HackingMarzipan/marzipanify/PDFViewer.app/Contents/MacOS/./PDFViewer Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  27. This is not the UIKit you're looking for » UIImpactFeedbackGenerator

    » UIPrintInfo » PHCachingImageManager » UIDocumentBrowser » UIViewController setNeedsUpdateOfHomeIndicatorAutoHidden Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  28. Automate #!/bin/bash rm -rf PDFViewer.app cp -r /Users/steipete/Builds/PDFViewer-.../Build/Products/Debug-iphonesimulator/PDFViewer.app . ./marzipanify

    PDFViewer.app rm Entitlements* lldb PDFViewer.app Wait and type run Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  29. Whitelist Swift (lldb) run Process 78797 launched: '/Users/steipete/Projects/HackingMarzipan/marzipanify /MarzipanPlatter-iOS.app/Contents/MacOS/MarzipanPlatter-iOS' (x86_64)

    dyld: Library not loaded: @rpath/libswiftAVFoundation.dylib Referenced from: /Users/steipete/Projects/HackingMarzipan/marzipanify/ MarzipanPlatter-iOS.app/Contents/MacOS/MarzipanPlatter-iOS Reason: no suitable image found. Did find: /Users/steipete/Projects/HackingMarzipan/marzipanify/MarzipanPlatter-iOS.app/ Contents/MacOS/../Frameworks/libswiftAVFoundation.dylib: mach-o, but not built for iOSMac Process 78797 stopped * thread #1, stop reason = signal SIGABRT frame #0: 0x000000010523a162 dyld`__abort_with_payload + 10 dyld`__abort_with_payload: -> 0x10523a162 <+10>: jae 0x10523a16c ; <+20> Target 0: (MarzipanPlatter-iOS) stopped. Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  30. Whitelist Swift Termination Reason: DYLD, [0x4] Symbol missing Dyld Error

    Message: Symbol not found: _$S8Dispatch0A3QoSV11unspecifiedACvau Referenced from: /Users/USER/*/MarzipanPl/Users/steipete/Projects/HackingMarzipan/ marzipanify/ViewerMac.app/Contents/MacOSatter-iOS.app/Contents/ MacOS/MarzipanPlatter-iOS (which was built for Mac OS X 12.0) Expected in: /Users/USER/*/MarzipanPlatter-iOS.app/Contents/MacOS/../Frameworks/libswiftDispatch.dylib /System/iOSSupport/dyld/macOS-whitelist.txt Append: /Applications/ViewerMac.app/Contents/MacOS Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  31. AppKit = no fun *** Terminating app due to uncaught

    exception 'NSInternalInconsistencyException', reason: 'AppKit is getting loaded into a disallowed context' *** First throw call stack: ( 0 CoreFoundation 0x00007fff4b49343d __exceptionPreprocess + 256 1 libobjc.A.dylib 0x00007fff772e1720 objc_exception_throw + 48 2 CoreFoundation 0x00007fff4b4ae08e +[NSException raise:format:arguments:] + 98 3 Foundation 0x00007fff4d82955d -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 194 4 AppKit 0x00007fff489175cb +[NSApplication load] + 672 5 libobjc.A.dylib 0x00007fff772d5629 call_load_methods + 693 6 libobjc.A.dylib 0x00007fff772d2758 load_images + 117 7 ??? 0x0000000114ec7454 0x0 + 4646007892 8 ??? 0x0000000114ed90c5 0x0 + 4646080709 9 ??? <…> Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  32. otool -L /System/Library/Frameworks/Photos.framework/Photos /System/Library/Frameworks/Photos.framework/Photos: /System/Library/Frameworks/Photos.framework/Versions/A/Photos /System/Library/PrivateFrameworks/TCC.framework/Versions/A/TCC /System/Library/PrivateFrameworks/PhotosImagingFoundation.framework/Versions/A/PhotosImagingFoundation /System/Library/PrivateFrameworks/CloudPhotoServices.framework/Versions/A/Frameworks/ CloudPhotoServicesConfiguration.framework/Versions/A/CloudPhotoServicesConfiguration /System/Library/Frameworks/CoreLocation.framework/Versions/A/CoreLocation

    /System/Library/PrivateFrameworks/CloudPhotoServices.framework/Versions/A/CloudPhotoServices /System/Library/PrivateFrameworks/PhotosFormats.framework/Versions/A/PhotosFormats /System/Library/PrivateFrameworks/PhotoLibraryPrivate.framework/Versions/A/PhotoLibraryPrivate /System/Library/PrivateFrameworks/PhotoFoundation.framework/Versions/A/PhotoFoundation /System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices /System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics /System/Library/Frameworks/CoreMedia.framework/Versions/A/CoreMedia /System/Library/Frameworks/AVFoundation.framework/Versions/A/AVFoundation /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation /usr/lib/libobjc.A.dylib /usr/lib/libSystem.B.dylib /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation /System/Library/Frameworks/ImageIO.framework/Versions/A/ImageIO Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  33. Set Deployment Target to iOS 12 Peter Steinberger - @steipete

    - Hacking Marzipan - try! Swift NYC 2018
  34. Patch missing methods setNeedsUpdateOfHomeIndicatorAutoHidden]: unrecognized selector sent to instance 0x10d83f600'

    Fix: (UIKit+iOSMacFixes.m) @interface UIViewController (MarzipanSupport) - (void)setNeedsUpdateOfHomeIndicatorAutoHidden; @end @implementation UIViewController (MarzipanSupport) - (void)setNeedsUpdateOfHomeIndicatorAutoHidden {} @end Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  35. Become a better Mac citizen Peter Steinberger - @steipete -

    Hacking Marzipan - try! Swift NYC 2018
  36. class iOSMacToolbarController { init() { print("iOSMac Marzipan extensions initializing.") guard

    (NSClassFromString("_UIWindowToolbarButtonItem") != nil) else { print("iOSMac UIKit Extensions not found.") return } let titleButton = _UIWindowToolbarButtonItem(identifier: "com.pspdfkit.viewer.test") titleButton?.title = "A button" guard let toolbarController = UIApplication.shared.keyWindow!. value(forKey: "_windowToolbarController") as? _UIWindowToolbarController else { print("iOSMac KVO error.") return } toolbarController.itemIdentifiers = ["com.pspdfkit.viewer.test"] toolbarController.templateItems = [titleButton] print("iOSMac extension initialized.") } } https://gist.github.com/steipete/b8bf675028ee476a9ca9af1ff14ff1e0
  37. It's never that easy... dyld: Symbol not found: _OBJC_CLASS_$__UIWindowToolbarButtonItem Referenced

    from: /Users/steipete/Library/Developer/CoreSimulator/Devices /43869E4F-C148-4D80-9E85-82466FAA8FED/data/Containers/Bundle/Application/ 6AFDFACD-0CD8-46FA-9F91-75B67B7A78F9/ViewerMac.app/ViewerMac Expected in: flat namespace in /Users/steipete/Library/Developer/CoreSimulator/Devices/ 43869E4F-C148-4D80-9E85-82466FAA8FED/data/Containers/Bundle/Application/ 6AFDFACD-0CD8-46FA-9F91-75B67B7A78F9/ViewerMac.app/ViewerMac (lldb) Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  38. Acknowledgements » Steven Troughton-Smith - @stroughtonsmith https:// github.com/steventroughtonsmith/marzipanify » Michael

    Thomas - @NSBiscuit https://github.com/ biscuitehh/MarzipanPlatter » !"#$ %&$#'( - @hbkirb http://kirb.me/2018/06/07/ iosmac-research.html » Vlas Voloshin - @argentumko https:// www.youtube.com/watch?v=EpUnke2yDug Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018
  39. Thanks! » Peter Steinberger, @steipete on Twitter » pdfviewer.io (iOS

    & Android, no macOS just yet :) » Let the madness begin. Peter Steinberger - @steipete - Hacking Marzipan - try! Swift NYC 2018