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

Dylib Hijacking on macOS: Dead or Alive?

Dylib Hijacking on macOS: Dead or Alive?

Over a decade ago, a much younger Patrick revealed how macOS (née OS X) was vulnerable to what had long been considered a Windows-only attack: dynamic library hijacking. At the time, he showed how simply planting malicious libraries in the right place could enable stealthy persistence, process injection, and even bypass core Apple security features.

Today, an older (and hopefully wiser) Patrick revisits the core concepts of that original research, explores how real-world macOS malware has abused the technique over the years, and examines how Apple responded with a series of aggressive mitigations aimed at stamping out such hijacks.

Finally, fast-forwarding to macOS 26, one burning question remains: is dynamic library hijacking finally dead, or still alive and well? Come for the history, stay for the live demos, detection tips, and yes, a few surprises.

Avatar for Patrick Wardle

Patrick Wardle

October 20, 2025
Tweet

More Decks by Patrick Wardle

Other Decks in Technology

Transcript

  1. WHAT YOU WILL LEARN Today, we'll explore "dylib hijacking" and

    the mitigations Apple has introduced to comprehensively(?) thwart it. /* Definitions */ Dependency: a library a program relies (depends) on to run. Loader: A program that loads an executable into memory, prepares it to run, and transfers control to it. On macOS, libraries are referred to as "dylibs", ...while the loader is named dyld
  2. % WHOAMI Patrick Wardle Objective-See DoubleYou Building core macOS detection

    components that integrate into larger enterprise security products ....with Mike S
  3. Processes ...as trusted entities A process (and its libraries) Security

    decisions are made at the process level ...and any libraries within it, are included decision! each process runs its own (protected) memory space Resource access (e.g. TCC access checks) Endpoint Security events ("responsible process") Entitlements (e.g. override SIP) 3rd-party security tools (e.g. firewalls, app auth.) "Process-level" (security) decisions:
  4. If an attacker loads a malicious library into a trusted

    process, they inherit its privileges and it becomes part of all process-level security decisions! ...and one way to do this is (was?) via "dylib hijacking" insert (malicious) code into a process Processes Injection
  5. History of dll/dylib hijacking Apple's Mitigations 1998: NSA (Window's NT

    Security guide) 2015: P. Wardle public "discovery" early 2000s: Georgi Guninski 2010: HD Moore public "discovery" RIP dylib hijacks?
  6. How are processes launched? ...by the loader! program (+dependencies in

    memory) program on disk loader (dyld) When a program is launched, dyld loads it into memory, resolves dependencies, and then hands off execution. On disk binary != In memory binary
  7. How are dependencies specified? by load commands, specifically via the

    LC_LOAD_DYLIB % otool -L /System/Applications/Calculator.app/Contents/MacOS/Calculator /usr/lib/libobjc.A.dylib /usr/lib/libSystem.B.dylib /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation /System/Library/PrivateFrameworks/Calculate.framework/Versions/A/Calculate /System/Library/PrivateFrameworks/CalculateUI.framework/Versions/A/CalculateUI .... % otool -l /System/Applications/Calculator.app/Contents/MacOS/Calculator ... Load command 17 cmd LC_LOAD_DYLIB cmdsize 56 name /usr/lib/libobjc.A.dylib (offset 24) compatibility version 1.0.0 each dependency described via a 'LC_LOAD_DYLIB' load command % otool -L Malware/Mokes/A/Mokes ... /System/Library/Frameworks/CoreWLAN.framework/Versions/A/CoreWLAN /System/Library/Frameworks/AVFoundation.framework/Versions/A/AVFoundation /System/Library/Frameworks/DiskArbitration.framework/Versions/A/DiskArbitration } OSX.Mokes dependencies malware analysis: insight into capabilities wifi scans webcam access monitoring for usbs
  8. Programs have dependencies that, so far, we’ve seen are defined

    using absolute paths. However, absolute paths don’t work well for internal dependencies (like those inside an app bundle) if the binary is moved. ...about non-absolute dependencies An observation if a program specifies a ("non-weak") dependency and its not found at load time, the program won't run! "...[you] want your binaries to be installable in anywhere on the disk" -Apple % tree "Foo.app" Foo.app └── Contents ├── Frameworks │ ├── bar.dylib ├── MacOS │ ├── Foo an app, with an "internal" dependency
  9. Run Path Dependencies (prefix: "@rpath") resolved based on the program's

    runtime location % otool -l Foo.App/Contents/MacOS/Foo Load command 14 cmd LC_LOAD_DYLIB cmdsize 56 name @rpath/foo.dylib Load command 104 cmd LC_RPATH cmdsize 32 path @executable_path Load command 105 cmd LC_RPATH cmdsize 32 path @loader_path Load command 106 cmd LC_RPATH cmdsize 48 path @executable_path/../Frameworks "run path" dependency "run path" dirs. The loader searches each run path (LC_RPATH) directory and blindly loads the first dylib it finds that matches the dependency's name 👀 @rpath/foo.dylib looks for the "rpath" dependency ...in each "rpath" directory (each specified in a LC_RPATH) % man dyld "@rpaths"
  10. So what is library hijacking? foo.dylib? foo.dylib? Multiple run path

    directories, The dependency is found in a secondary run path dir. Imagine a binary with: note: not all binaries are "vulnerable" ...also, this isn't the binary's fault per se! Drop a library, with the same name, in a primary search location ...hijack! (no need to modify the binary)
  11. Impact? (circa 2015) persistence, code injection, gatekeeper bypasses, & more!

    in everything was hijackable! hijackable apps on my box $ reboot $ lsof -p <pid of PhotoStreamAgent> /Applications/iPhoto.app/Contents/Library/LoginItems/ PhotoFoundation.framework/Versions/A/PhotoFoundation /Applications/iPhoto.app/Contents/Frameworks/ PhotoFoundation.framework/Versions/A/PhotoFoundation code injection into Xcode (do you trust your compiler?) stealthy persistence (via Apple's PhotoStreamAgent) Gatekeeper bypass via 'externally' referenced dylibs
  12. Always an Impact? only if vulnerable app is "useful" CVE-2025-56383

    (Sept. 2025) "millions of [Windows] users at risk" Ok, but really this only allows local attackers to load a library in Notepad++ 🤪 infosec twitter (x) ...remains undefeated
  13. "Remote" Mitigation ("quick fix") patch for CVE 2015-3715 (external dylibs)

    $ classdump XprotectFramework @interface XprotectDylibCheck : NSObject { NSMutableArray *_rPaths; NSMutableArray *_loadCommands; .... } + (BOOL)path:(id)arg1 isSafeWithBundle:(id)arg2; + (id)allowedLibraryPaths; - (BOOL)checkCommandsWithBundleURL:(id)arg1; if (![self path:dylib isSafeWithBundle:bundle]) { //NOT SAFE: block/log "Fails dylib check" } 01 02 03 (lldb) po $rax <__NSArrayI 0x7f89ca4ed960>( /usr/, /opt, /System/, /Library/, /Network/, /AppleInternal/, /Developer, /build ) dylib in "allowed" dirs? if(YES != [dylib hasPrefix:appBundle]) { //NOT SAFE } 01 02 03 dylib is in app bundle? } checks each dependency (e.g. LC_LOAD_DYLIB) external dylib hijack
  14. "Remote" Mitigations (more generally) gatekeeper path randomization, a.k.a. 'translocation' "What's

    New in Security" (WWDC 2016) bundle with external (hijackable?) content isolated app (no external content) only bundle is copied ...then exec'd disk image, zip, etc. * Any references to (untrusted) external content are therefore severed * 💥
  15. "Remote" Mitigations gatekeeper path randomization a.k.a. translocation # ./processMonitor {

    "event" : "ES_EVENT_TYPE_NOTIFY_EXEC", "process" : { "pid" : 4112 "name" : "Adobe Photoshop 2025", "path" : "/private/var/folders/tp/j1m5l84j72d4qdmqhbyr6j3c0000gn/T/AppTranslocation/ A73C93FD-0166-44D7-9A3A-C0DC91300BB3/d/Adobe Photoshop 2025.app/Contents/MacOS/Adobe Photoshop 2025", ... } } % ps 4112 PID COMMAND 4112 /private/var/folders/tp/j1m5l84j72d4qdmqhbyr6j3c0000gn/T/AppTranslocation/ A73C93FD-0166-44D7-9A3A-C0DC91300BB3/d/Adobe Photoshop 2025.app/Contents/MacOS/Adobe Photoshop 2025 "App Translocation" folders: Are randomly named Are read-only Contain only the app bundle (nothing external!) app executed from a translocated path .../AppTranslocation/... Learn more: "'Untranslocating' an App" objective-see.org/blog/blog_0x15.html
  16. "Remote" Mitigations (more generally) notarization downloaded code, must be notarized!

    macOS will not load a hijacker dylib, even if it's "distributed" with a trusted app. developers must submit binaries for notarization prior to distribution notarization check
  17. Local Mitigations "library validation" via the Hardened Runtime even if

    a app is vulnerable to a dylib hijack macOS will no longer load the hijacker's dylib! Signed by Apple (e.g. system library) Signed with app's team ID Library Validation, all loaded dylibs must be: or a suggestion (2016) in 2018 Apple listens!? 🤯
  18. Local Mitigations TCC/Gatekeeper improvements "What's New in Privacy" (WWDC 2022)

    "Gatekeeper will validate the integrity of all notarized apps on first launch ...additionally, Gatekeeper will attempt to block unauthorized tampering attempts alerting the user" -Brandon Dalton vulnerable app local attacker ...attempting app subversion (hijack?) so now, even privileged (local) attackers cannot modify app bundles!
  19. TAKEAWAYS "dylib hijacking" on macOS was a massive security issue

    ! ...RIP dylib hijacking But Apple responded ...quickly & resoundingly : Notarization Translocation Library Validation App Protection (TCC/GK checks)
  20. Bypassing Translocation ...by symlinking to the application's binary not translocated

    ! If the user clicks the app, it gets translocated prior to launch ...but if the user clicks a symlink to the app's binary, it's not!? disk image symlink + hidden bundle + external (?) app is *not* translocated
  21. "Remotely" Exploiting? "relative" external components still viable Anything that loads

    or runs external content (normally blocked by app translocation) is now fair game! For example: create an app that executes commands from a config file in its working directory, ...omit the file when notarizing, include it later during deployment! Create benign app with (reflective) "updater" dylib Submit for notarization 🤞 Package up "updater" with an "externally" vulnerable but legitimate (trusted/notarized) app externally hijackable + w/ no library validation!
  22. Local Hijacks % otool -l <some binary> ... Load command

    14 cmd LC_LOAD_DYLIB cmdsize 56 name @rpath/<some>.dylib Load command 104 cmd LC_RPATH cmdsize 32 path @executable_path Load command 105 cmd LC_RPATH cmdsize 32 path @loader_path Load command 106 cmd LC_RPATH cmdsize 48 path @executable_path/../Frameworks "run path" dependency multiple "run paths" Has 'rpath' dependency Has multiple LC_RPATH dirs. Dependency found in secondary dir. No hardened runtime (or 'library validation' disabled) is vulnerable? hijack, by planting dylib in primary directory! Recall that, the loader searches each run path (LC_RPATH) directory and loads the first dylib it finds that matches the dependency's name! ...first, how to find "vulnerable" apps Is 3rd-party program
  23. Local Hijacks via Objective-See's "Dylib Hijack Scanner" //scan all LC_LOAD_DYLIBS

    for(NSString* loadDylib in binary.parserInstance.binaryInfo[KEY_LC_LOAD_DYLIBS]) { //skip dylibs that are imported normally (e.g. without '@rpath') if(YES != [loadDylib hasPrefix:RUN_SEARCH_PATH]) { continue; } //grab first run path directory firstRPathDirectory = [binary.parserInstance.binaryInfo[KEY_LC_RPATHS] firstObject]; //"resolve" dylib path using run path absoluteDylib = [firstRPathDirectory stringByAppendingPathComponent: [loadDylib substringFromIndex:"@rpath".length]]; //is candidate // not found, not in dyld cache, not SIP'd etc if(YES == [self isCandidate:absoluteDylib]) { //"VULNERABILITY" DETECTED! // dylib isn't found in first run-path search directory! } ... 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 dylib hijacker detection
  24. Hijacking Photoshop (libtbb.12.6.dylib) ...to craft a stealthy 'trusted' implant! %

    otool -l "Adobe Photoshop 2025.app/Contents/MacOS/Adobe Photoshop 2025" ... Load command 14 cmd LC_LOAD_DYLIB cmdsize 56 name @rpath/libtbb.12.6.dylib Load command 104 cmd LC_RPATH cmdsize 32 path @executable_path ... Load command 106 cmd LC_RPATH cmdsize 48 path @executable_path/../Frameworks a "run-path" dependency multiple "run-paths" legit libtbb.12.6.dylib malicious libtbb.12.6.dylib Since the libtbb.12.6.dylib exists in a secondary location and Photoshop has disabled library validation, can we hijack it!? Contents/MacOS Frameworks/ Disabled lib. validation
  25. Crafting a Compatible Hijacker version # must match, and exports

    must be taken care of! % open "Adobe Photoshop 2025.app" dyld: Library not loaded: @rpath/libtbb.12.6.dylib Referenced from: "Adobe Photoshop 2025.app/Contents/MacOS/Adobe Photoshop 2025" Reason: Incompatible library version: Adobe Photoshop 2025.app requires version 1.0.0 or later, but libtbb.12.6.dylib provides version 0.0.0 Trace/BPT trap: 5 % open "Adobe Photoshop 2025.app" dyld: Symbol not found: '_TBB_runtime_version' Referenced from: "Adobe Photoshop 2025.app/Contents/MacOS/Adobe Photoshop 2025" Expected in: "Adobe Photoshop 2025.app/Contents/MacOS/Adobe Photoshop 2025/libtbb.12.6.dylib" Trace/BPT trap: 5 The hijacker library must match in name, version, but also provide the expected exports, otherwise the loader with throw an exception
  26. Crafting a Compatible Hijacker re-exporting exports to original library dylib

    % dyld_info -exports "Adobe Photoshop 2025.app/Contents/Frameworks/libtbb.12.6.dylib" | c++filt offset symbol 0x00018234 _TBB_runtime_interface_version 0x0001823F _TBB_runtime_version 0x00013360 tbb::detail::r1::deallocate(tbb::detail::d1::small_object_pool&, void*, unsigned long) 0x0000402C tbb::detail::r1::initialize(tbb::detail::d1::task_arena_base&) 0x0001801A tbb::detail::r1::initialize(tbb::detail::d1::task_group_context&) 0x000125EE tbb::detail::r1::try_acquire(tbb::detail::d1::queuing_rw_mutex&, tbb::detail::d1::queuing_rw_mutex::scoped_lock&, bool) 0x00012DE7 tbb::detail::r1::try_acquire(tbb::detail::d1::rtm_mutex&, tbb::detail::d1::rtm_mutex::scoped_lock&) 0x000122FE tbb::detail::r1::itt_task_end(tbb::detail::d1::itt_domain_enum) 0x00012F1F tbb::detail::r1::acquire_reader(tbb::detail::d1::rtm_rw_mutex&, tbb::detail::d1::rtm_rw_mutex::scoped_lock&, bool) At compile time: -Xlinker -reexport_library <original dylib> install_name_tool -change to set absolute path hijacker orignal "re-export" (legitimate) libtbb.12.6.dylib's exports
  27. Crafting a Compatible Hijacker re-exporting exports to original library dylib

    % tree "Adobe Photoshop 2025.app" Adobe Photoshop 2025.app └── Contents ├── Frameworks │ ... │ ├── libtbb.12.6.dylib ├── Info.plist ├── MacOS │ ├── Adobe Photoshop 2025 │ ├── libtbb.12.6.dylib original: Contents/Frameworks/libtbb.12.6.dylib hijacker: Contents/MacOS/libtbb.12.6.dylib % otool -l "Adobe Photoshop 2025.app/Contents/MacOS/libtbb.12.6.dylib" ... Load command 11 cmd LC_REEXPORT_DYLIB cmdsize 128 name /Applications/Adobe Photoshop 2025/Adobe Photoshop 2025.app/Contents/Frameworks/libtbb.12.6.dylib MacOS/libtbb.12.6.dylib Frameworks/libtbb.12.6.dylib "re-export" Photoshop hijacked Photoshop
  28. Bypassing "App Protection" ? as macOS protects apps & re-validates

    on (re)launch % sudo cp libtbb.12.6.dylib "/Applications/Adobe Photoshop 2025/Adobe Photoshop 2025.app/Contents/MacOS/ cp: /Applications/Adobe Photoshop 2025/Adobe Photoshop 2025.app/Contents/MacOS/libtbb.12.6.dylib: Operation not permitted (even as root) cannot modify application directly /Applications /tmp Copy via ditto Add hijacker dylib Copy back via ditto ...but on launch, will (re)trigger a verification "safe" to replace apps as they contain no (user) data!
  29. Benefits of our Hijack stealthy "persistence" with a high level

    of inherited trust % "/Applications/Adobe Photoshop 2025/Adobe Photoshop 2025.app/Contents/MacOS/Adobe Photoshop 2025" [+] Injected fake libtbb.12.6.dylib loaded by: /Applications/Adobe Photoshop 2025/Adobe Photoshop 2025.app/Contents/MacOS/Adobe Photoshop 2025 Access to files (TCC bypass): Access to network (LuLu): loaded hijacker dylib no impact to functionality
  30. Security Tools? dylib hijack vs. LuLu (firewall) LuLu's code signing

    checks via SecCodeCopySigningInformation (audit token -> dynamic code ref) + verified with SecCodeCheckValidity //matched rule // make sure code signing info (still) matches! if(YES != matchesCSInfo(process.csInfo, csInfo)) { os_log_error(logHandle, "ERROR: code signing mismatch: %{public}@ / %{public}@", process.csInfo, csInfo); goto bail; } 01 02 03 04 05 06 07 BOOL matchesCSInfo(NSDictionary* csInfo_1, NSDictionary* csInfo_2) { //first check status (e.g. ensure we're still validly signed)! //then check signer and code signing ID and signing authorities } 01 02 03 04 a LuLu rule: allow photoshop Apple's Runtime code signing APIs are limited to the main process 🤷
  31. Security Tools? dylib hijack vs. endpoint security # eslogger open

    { "event": { "open": { "file": { "path": "\/Users\/patrick\/Documents\/secret.txt" } }, "process": { "executable": { "path": "\/Applications\/Adobe Photoshop 2025\/Adobe Photoshop 2025.app\/Contents\/MacOS\/Adobe Photoshop 2025", "team_id": "JQ525L2MZD", "signing_id": "com.adobe.Photoshop" ... }, ... } Granularity: "responsible process" process level (including code signing information) file access (ES_EVENT_TYPE_AUTH_OPEN) responsible process: Photoshop
  32. Security Tools? dylib hijack vs. Santa # santactl fileinfo "/Applications/Adobe

    Photoshop 2025/Adobe Photoshop 2025.app" Path : /Applications/Adobe Photoshop 2025/Adobe Photoshop 2025.app/Contents/MacOS/Adobe Photoshop 2025 ... Team ID : JQ525L2MZD # sudo santactl rule --allow --teamid --identifier JQ525L2MZD Added rule for Team ID: JQ525L2MZD. # tail -f /var/db/santa/santa.log santad: action=EXEC|decision=ALLOW|reason=TEAMID|sha256=c74fee63c5cd642bc90f52366992747effa9f797a1785cbe07578cffa65e3c31| cert_sha256=9ff4333283ec0a959965925f1ea235a6fe438ded8feab28d238d8a564195a0a4|cert_cn=Developer ID Application: Adobe Inc. (JQ525L2MZD)|teamid=JQ525L2MZD|pid=22808|pidversion=60782|ppid=1|uid=501|user=patrick|gid=20|group=staff|mode=M|path=/ Applications/Adobe Photoshop 2025/Adobe Photoshop 2025.app/Contents/MacOS/Adobe Photoshop 2025|args=/Applications/Adobe Photoshop 2025/Adobe Photoshop 2025.app/Contents/MacOS/Adobe Photoshop 2025 (before hijacking) create Santa rule to allow Photoshop (e.g. via teamID) dylib hijack app Subsequent app launches are allowed, even though app is subverted!
  33. Static Detection multiple (run-path) dylibs w/ same name in different

    dirs. list of run path directories (load command: LC_RPATH) @rpath/<some>.dylib } If you encounter multiple instances of a "run-path" dylib (in multiple run-path directories), the app may be hijacked! esp. if dylib code signing doesn't match !
  34. Static Detection multiple (run-path) dylibs w/ same name in different

    dirs. //iterate overall all dependencies for(NSString* dependency in binary.parserInstance.binaryInfo[KEY_LC_LOAD_DYLIBS]) { int dylibCount = 0; //skip non-rpath'd dependencies if(![dependency hasPrefix:@"@rpath"]) { continue; } //check all run path directories for(NSString* runPath in binary.parserInstance.binaryInfo[KEY_LC_RPATHS]) { //build full path path = [runPath stringByAppendingPathComponent:dependency substringFromIndex:"@rpath".length]]; //does it exist? if([NSFileManager.defaultManager fileExistsAtPath:path]){ dylibCount++; } //more than one dylib w/ same name? if(dylibCount == 2) { //potential hijack! } ... 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 check for LC_REEXPORT_DYLIB too ?
  35. Static "Runtime" Detection? verify codesigning of entire bundle? //create static

    code ref via path status = SecStaticCodeCreateWithPath((__bridge CFURLRef)([NSURL fileURLWithPath:path]), kSecCSDefaultFlags, &code); if(errSecSuccess != status) { //handle error } //check signature (validates entire bundle: code, nested code, etc.) SecCSFlags flags = kSecCSCheckNestedCode | kSecCSCheckAllArchitectures | kSecCSStrictValidate; status = SecStaticCodeCheckValidity(code, flags, NULL); if(errSecSuccess != status) { //handle error } //extract signing info status = SecCodeCopySigningInformation(code, kSecCSSigningInformation, &signingDetails); if(errSecSuccess != status) { //handle error } 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 code signing verification / extraction though very slow :\ ...if macOS was doing it's job, we wouldn't be in this conundrum! hijacked Photoshop ...invalidly signed!
  36. Runtime Detection via vmmap as Apple doesn't trust us to

    enumerate loaded library directly % vmmap $(pgrep Photoshop) Process: Adobe Photoshop 2025 [14792] Path: /Applications/Adobe Photoshop 2025/Adobe Photoshop 2025.app/Contents/MacOS/Adobe Photoshop 2025 Code Type: ARM64 ==== Non-writable regions for process 14792 REGION TYPE START - END REGION DETAIL __TEXT 102084000-10ad64000 /Applications/Adobe Photoshop 2025/Adobe Photoshop 2025.app/Contents/MacOS/Adobe Photoshop 2025 __DATA_CONST 10ad64000-10b4e0000 /Applications/Adobe Photoshop 2025/Adobe Photoshop 2025.app/Contents/MacOS/Adobe Photoshop 2025 ... __TEXT 10c00c000-10c010000 /Applications/Adobe Photoshop 2025/Adobe Photoshop 2025.app/Contents/MacOS/libtbb.12.6.dylib __DATA_CONST 10c010000-10c014000 /Applications/Adobe Photoshop 2025/Adobe Photoshop 2025.app/Contents/MacOS/libtbb.12.6.dylib ... __TEXT 10cd08000-10cd24000 /Applications/Adobe Photoshop 2025/Adobe Photoshop 2025.app/Contents/Frameworks/libtbb.12.6.dylib __DATA_CONST 10cd24000-10cd28000 /Applications/Adobe Photoshop 2025/Adobe Photoshop 2025.app/Contents/Frameworks/libtbb.12.6.dylib Enumerate loaded libraries (vmmap) Identify library name "collisions" Eliminate false positives by checking code signing formation unless hijacker dylib reflectively loads another payload then unloads 🫣
  37. Preventing Dylib Hijacking Apple is so close to eradicating this

    wholly! Fix: "App Translocation" Fix: App Validation ...why not just translocate any downloaded binary ? ...why is this broken?
  38. "Dylib hijacking on OS X" www.virusbulletin.com/virusbulletin/2015/03/dylib-hijacking-os-x Dead or Alive dylib

    hijacking on macOS RESOURCES: "Tweaking macOS security controls to thwart application bundle manipulation" redcanary.com/blog/threat-detection/mac-application-bundles/ "What's New in Security" (WWDC 2016) devstreaming-cdn.apple.com/videos/wwdc/2016/706sgjvzkvg6rrg9icw/706/706_whats_new_in_security.pdf