$30 off During Our Annual Pro Sale. View Details »

Getting started with making macOS utility app using private APIs

Yoshimasa Niwa
September 08, 2019

Getting started with making macOS utility app using private APIs

While using macOS day to day life, you may feel something is missing, or probably you may find repeating yourself and need some help by the tools or utilities.

In this talk, based on the experiences to make a TouchBar utility app, HapticKey, we will discuss how to make a macOS utility app stays in the status bar. Also, we will see how to reverse engineering macOS undocumented private APIs to provide utility functionalities.

Expected audiences and knowledge:
- Those who want to improve their day to day life by themselves.
- Intermediate level of Apple platform knowledge.
- Beginner level of Objective-C knowledge.

The goal of this talk:
- Make `NSStatusBar` utility application.
- Reverse engineering undocumented private APIs and use it.

Following topics are non-goal of this talk:
- Basic knowledge about how to use Xcode
- Security problems related to reverse engineering.
- Swift

Yoshimasa Niwa

September 08, 2019
Tweet

More Decks by Yoshimasa Niwa

Other Decks in Programming

Transcript

  1. Using Private APIs
    Getting Started with

    Making macOS Utility App
    Yoshimasa Niwa
    9/8/2019 — TIME SHARING ࢛୩

    macOS native symposium #05

    View Slide

  2. @niw

    Yoshimasa Niwa

    View Slide

  3. Do you like it?
    Touch Bar

    View Slide

  4. A simple utility application to trigger haptic feedback when tapping Touch Bar
    Haptic Key

    View Slide

  5. github.com/niw/HapticKey

    View Slide

  6. Today’s presentation
    Topics
    1. We have no windows
    2. We launch app when login
    3. We watches Touch Bar events
    4. We use track pad actuator

    View Slide

  7. No, no, we don’t need !
    No windows

    View Slide

  8. View Slide

  9. View Slide

  10. statusItemWithLength:
    NSStatusBarItem
    • applicationDidFinishLaunching: is still
    application entry point
    • Create NSStatusBarItem from NSStatusBar
    • Use
    NSStatusItemBehaviorRemovalAllowed to
    let users to arrange items in status bar.

    The position is persistent in NSUserDefaults

    View Slide

  11. View Slide

  12. LSUIElement is YES
    Hide dock icon
    • In Info.plist, set Application is agent (UIElement)
    to YES
    • That’s it

    View Slide

  13. A few additional things
    Caveats
    • Provide a way to quit app, or user can’t quit app
    • Status bar menu is the main user interface to
    communicate with users. Provide simple, intuitive
    menu items
    • Status bar icon may represent application
    state, such as enabled, disabled

    View Slide

  14. But we have status bar item and menu
    No main window
    • Use NSStatusBar and NSStatusBarItem
    • Set LSUIElement to YES
    • Status bar menu is the main user interface

    View Slide

  15. Login item, you’re so… ☹
    Launch app when login

    View Slide

  16. You might see this
    Start on Login

    View Slide

  17. You might know this preference
    Login Items

    View Slide

  18. You might find this API
    SMLoginItemSetEnabled
    • Enable a helper application located in the main
    application bundle’s “Contents/Library/LoginItems”
    directory

    View Slide

  19. View Slide

  20. Useless, unless you need to put your app in App Store
    SMLoginItemSetEnabled
    • It never work if you have two copy of
    application bundles that have same bundle
    identifier … and you will always have the two or more
    of them in the derived data and the archives
    • This is not adding Login Item to the account
    preferences. Completely different logic and more
    similar to /Library/LaunchAgents

    View Slide


  21. View Slide

  22. This is the one you need
    LSSharedFileList
    • Deprecated but still supported
    • You can add, remove Login Item
    • You can observe Login Item changes

    View Slide


  23. View Slide

  24. Example code seems working
    LSSharedFileList
    LSSharedFileListRef fileList = LSSharedFileListCreate(NULL,

    kLSSharedFileListSessionLoginItems, NULL);
    LSSharedFileListAddObserver(fileList, ..., callback, ...);
    void callback(LSSharedFileListRef fileList, void *context) {
    NSArray *snapshot = (__bridge NSArray *)

    LSSharedFileListCopySnapshot(fileList, ...);

    for (item in snapshot) {
    CFURLRef url;
    LSSharedFileListItemResolve(item, ..., &url);
    if ([(__bridge NSURL *)url isEqualTo:applicationBundlerURL]) {
    // changed!
    }
    }
    }

    View Slide

  25. View Slide

  26. NSDistributedNotificationCenter stops working
    LSUIElement app is always inactive
    • LSSharedFileList is using
    NSDistributedNotificationCenter
    • LSUIElement app is always inactive
    • NSDistributedNotificationCenter will not
    deliver any notifications if app is inactive

    View Slide

  27. NSNotificationSuspensionBehaviorDeliverImmediately
    Listen com.apple.private.BackgroundItemsChang
    • LSSharedFileList listens
    com.apple.private.BackgroundItemsChan
    geNotification
    • If the application process listens that notification as
    well with
    NSNotificationSuspensionBehaviorDeliv
    erImmediately option, LSSharedFileList
    can also listen it

    View Slide

  28. https://github.com/niw/HapticKey/blob/master/
    HapticKey/Classes/HTKLoginItem.m

    View Slide

  29. • SMLoginItemSetEnabled is not what we want
    • LSSharedFileList is the one
    • LSUIElement app also need to listen
    com.apple.private.BackgroundItemsChan
    geNotification
    LSSharedFileList is the one but requires some tricks
    Launch app when login

    View Slide

  30. We’re watching you
    Touch Bar events

    View Slide

  31. View Slide

  32. View Slide

  33. https://docs.google.com/presentation/d/
    1nEaiPUduh1vjks0rDVRTcJaEULbSWWh1tVdG2HF_XSU/edit?usp=sharing

    View Slide

  34. Overview
    ● macOS provides several APIs for event observing.
    ○ [NSView keyDown]
    ○ [NSApplication sendEvent]
    ○ CGEventTapCreate, [NSEvent addGlobalMonitorForEvents]
    ○ IOHIDQueueRegisterValueAvailableCallback
    ○ etc.
    ● macOS Catalina (10.15) will require a user approval of input monitoring for
    security. (Congratulation!)
    https://docs.google.com/presentation/d/1nEaiPUduh1vjks0rDVRTcJaEULbSWWh1tVdG2HF_XSU/edit?usp=sharing

    View Slide

  35. We can listen system event
    • CGEventTapCreate with event masks to listen
    specific events
    • We can listen keyboard events such as Fn keys
    • We can listen gesture events, which includes taps
    on Touch Bar
    CGEventTap

    View Slide

  36. Listener
    Feedback
    Key event, Tap event, …
    Haptic, Sound, Screen, …
    Event


    View Slide

  37. Don’t hide it or we will find it
    Private API

    View Slide

  38. API is a set of functions that many application can use
    What is API?
    • macOS API is provided in shared libraries
    • In form of C or Objective-C or Swift
    • Newer API may not be implemented in Objective-C
    • Application are using shared libraries through
    dyld(1)

    View Slide

  39. Public API is pubic because it is public
    Why public API is public?
    • Public API is public because it is documented
    • Public API is public because its name is visible
    • Public API is public because it is allowed to access
    from the application

    View Slide

  40. Private API is private because it’s not public
    Why private API is private?
    • Private API is private because it is not documented
    • Private API is private because its name is not visible
    • Private API is private because it is not allowed to
    access from the application

    View Slide

  41. Private API is private because it’s not public
    Why private API is private?
    • Private API is private because it is not documented
    • Private API is private because its name is not visible
    • Private API is private because it is not allowed to
    access from the application

    View Slide

  42. A container contains all related resources
    Framework Bundle
    • API is in shared library, which is lay outed
    in .framework bundle format
    • Public one is in /System/Library/Frameworks
    • Private our is in /System/Library/
    PrivateFrameworks

    View Slide

  43. /System/Library/PrivateFrameworks/MultitouchSupport.framework
    Use MultitouchSupport
    • A private framework that provides multitouch track
    pad related functions on macOS
    • This framework also provides track pad vibration

    View Slide

  44. Well, I was too lazy to make slides…
    Hands-on

    View Slide

  45. Command line tools
    Hands-on tools
    • Use nm -m dylib to find exported function names
    • Use otool -t -V -p function dylib to
    disassemble function
    • Use clang -iframework /System/
    Library/PrivateFrameworks -framework
    framework to link private framework

    View Slide

  46. Example code
    @import Foundation;
    @import IOKit;
    CF_EXPORT CFTypeRef
    MTActuatorCreateFromDeviceID(UInt64 deviceID);
    CF_EXPORT IOReturn MTActuatorOpen(CFTypeRef
    actuatorRef);
    CF_EXPORT IOReturn MTActuatorClose(CFTypeRef
    actuatorRef);
    CF_EXPORT IOReturn MTActuatorActuate(CFTypeRef
    actuatorRef, SInt32 actuationID, UInt32
    unknown1, Float32 unknown2, Float32 unknown3);
    int main() {
    IOReturn error;
    CFTypeRef actuatorRef =
    MTActuatorCreateFromDeviceID(0x200000001000000
    );

    if (!actuatorRef) {

    return -1;

    }
    error = MTActuatorOpen(actuatorRef);

    if (error != kIOReturnSuccess) {

    CFRelease(actuatorRef);

    return -1;

    }
    error = MTActuatorActuate(actuatorRef, 6,
    0, 0, 0.2);
    error = MTActuatorClose(actuatorRef);
    CFRelease(actuatorRef);

    actuatorRef = NULL;
    return 0;
    }
    Hands-on sample

    View Slide

  47. https://github.com/niw/HapticKey/blob/master/
    HapticKey/Classes/HTKMultitouchActuator.m

    View Slide

  48. Disassembling, researching and guessing.
    Private API
    • nm, otool, and also lldb
    • Hopper Disassembler is the tool helps your
    research
    • Always guess how API is designed and works

    View Slide

  49. Questions?
    Q&A

    View Slide