├── Injected Code ├── macOS 10.14 │ ├── amfid.hop │ ├── InjectedCode.hop │ ├── amfid (Original) │ ├── InjectedCode.xcodeproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ ├── xcshareddata │ │ │ └── xcschemes │ │ │ │ └── InjectedCode.xcscheme │ │ └── project.pbxproj │ ├── InjectedCode │ │ ├── main.c │ │ ├── Injection.h │ │ └── Injection.c │ └── Notes.txt └── macOS 10.14.4 │ ├── amfid.hop │ ├── InjectedCode.hop │ ├── amfid (Original) │ └── Notes.txt ├── AirPlayEnabler ├── AirPlayEnabler-Bridging-Header.h ├── XPC Service │ ├── XPCServiceImplementation.swift │ ├── XPCServiceImplementation+IsPrivilegedHelperRunning.swift │ ├── XPCServiceImplementation+GetPrivilegedHelperVersion.swift │ ├── XPCService.swift │ └── XPCServiceImplementation+UninstallPrivilegedHelper.swift ├── Code Injection │ ├── ExecutableInfo+AddressInTaskSpace.swift │ ├── Patch+DynamicCreation.swift │ ├── ExecutableInfo+ByteOrder.swift │ ├── Low-Level Functions │ │ ├── ImageInfo.h │ │ ├── Common.h │ │ ├── ExecutableInfo.h │ │ ├── Common.m │ │ ├── ImageInfo.m │ │ └── ExecutableInfo.m │ ├── InjectedCode+ExternalSymbolInfo.swift │ ├── Patch+Requirement.swift │ ├── Data+TaskVM.swift │ ├── InjectedCode+Data.swift │ ├── MemoryData.swift │ ├── InjectedCode.swift │ ├── Patch.swift │ ├── CodeInjector.swift │ └── Patches │ │ ├── Patch+MacOS10_14.swift │ │ └── Patch+MacOS10_14_4.swift ├── Launchd.plist ├── main.swift ├── Extensions and Utilities │ ├── ActivityTracing.swift │ ├── ActivityTracing.m │ ├── PrivilegedHelperInfo.swift │ └── ActivityTracing.h └── Info.plist ├── AirPlayEnablerInterface ├── AirPlayEnablerInterfaceError.swift ├── AirPlayEnablerInterface.swift └── PrivilegedHelperVersion.swift ├── README.md └── AirPlayEnabler.xcodeproj └── project.pbxproj /Injected Code/macOS 10.14/amfid.hop: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Optimus-Player/AirPlay-Enabler/HEAD/Injected Code/macOS 10.14/amfid.hop -------------------------------------------------------------------------------- /Injected Code/macOS 10.14.4/amfid.hop: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Optimus-Player/AirPlay-Enabler/HEAD/Injected Code/macOS 10.14.4/amfid.hop -------------------------------------------------------------------------------- /Injected Code/macOS 10.14/InjectedCode.hop: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Optimus-Player/AirPlay-Enabler/HEAD/Injected Code/macOS 10.14/InjectedCode.hop -------------------------------------------------------------------------------- /Injected Code/macOS 10.14/amfid (Original): -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Optimus-Player/AirPlay-Enabler/HEAD/Injected Code/macOS 10.14/amfid (Original) -------------------------------------------------------------------------------- /Injected Code/macOS 10.14.4/InjectedCode.hop: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Optimus-Player/AirPlay-Enabler/HEAD/Injected Code/macOS 10.14.4/InjectedCode.hop -------------------------------------------------------------------------------- /Injected Code/macOS 10.14.4/amfid (Original): -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Optimus-Player/AirPlay-Enabler/HEAD/Injected Code/macOS 10.14.4/amfid (Original) -------------------------------------------------------------------------------- /Injected Code/macOS 10.14.4/Notes.txt: -------------------------------------------------------------------------------- 1 | Similar to macOS 10.14 except for amount of free space and different addresses. 2 | 3 | amfid Capacity: 4 | 0x100007af0 to 0x100007fff => 0x510 5 | -------------------------------------------------------------------------------- /AirPlayEnabler/AirPlayEnabler-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import "ExecutableInfo.h" 6 | #import "ActivityTracing.h" 7 | -------------------------------------------------------------------------------- /Injected Code/macOS 10.14/InjectedCode.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AirPlayEnabler/XPC Service/XPCServiceImplementation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // XPCServiceImplementation.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-18. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | import AirPlayEnablerInterface 10 | 11 | class XPCServiceImplementation: AirPlayEnablerInterface { 12 | } 13 | -------------------------------------------------------------------------------- /Injected Code/macOS 10.14/InjectedCode/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // main.c 3 | // InjectedCode 4 | // 5 | // Created by Darren Mo on 2018-12-20. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | #include "Injection.h" 10 | 11 | int main(int argc, const char * argv[]) { 12 | RunInjectedCode(NULL, 0, NULL, 0); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /Injected Code/macOS 10.14/InjectedCode.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Injected Code/macOS 10.14/InjectedCode/Injection.h: -------------------------------------------------------------------------------- 1 | // 2 | // Injection.h 3 | // InjectedCode 4 | // 5 | // Created by Darren Mo on 2018-12-20. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | #ifndef Injection_h 10 | #define Injection_h 11 | 12 | #include 13 | 14 | OSStatus RunInjectedCode(SecStaticCodeRef staticCode, uint64_t arg1, bool *arg2, uint64_t arg3); 15 | 16 | #endif /* Injection_h */ 17 | -------------------------------------------------------------------------------- /AirPlayEnabler/Code Injection/ExecutableInfo+AddressInTaskSpace.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExecutableInfo+AddressInTaskSpace.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-21. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | extension ExecutableInfo { 10 | func addressInTaskSpace(fromAddressInExecutableFile addressInExecutableFile: mach_vm_address_t) -> mach_vm_address_t { 11 | return addressInExecutableFile + aslrOffset 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /AirPlayEnabler/Launchd.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Label 6 | mo.darren.optimus.player.mac.airplay-enabler 7 | RunAtLoad 8 | 9 | KeepAlive 10 | 11 | MachServices 12 | 13 | mo.darren.optimus.player.mac.airplay-enabler 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /AirPlayEnabler/XPC Service/XPCServiceImplementation+IsPrivilegedHelperRunning.swift: -------------------------------------------------------------------------------- 1 | // 2 | // XPCServiceImplementation+IsPrivilegedHelperRunning.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-19. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | extension XPCServiceImplementation { 10 | func isPrivilegedHelperRunning(withReply reply: @escaping () -> Void) { 11 | OSInitiateActivity(named: "\(type(of: self)).\(#function)") { 12 | reply() 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /AirPlayEnabler/XPC Service/XPCServiceImplementation+GetPrivilegedHelperVersion.swift: -------------------------------------------------------------------------------- 1 | // 2 | // XPCServiceImplementation+GetPrivilegedHelperVersion.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-20. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | import AirPlayEnablerInterface 10 | 11 | extension XPCServiceImplementation { 12 | func getPrivilegedHelperVersion(withReply reply: @escaping (_ version: PrivilegedHelperVersion) -> Void) { 13 | OSInitiateActivity(named: "\(type(of: self)).\(#function)") { 14 | reply(PrivilegedHelperInfo.shared.version) 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /AirPlayEnabler/Code Injection/Patch+DynamicCreation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Patch+DynamicCreation.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-21. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Patch { 12 | static func makePatchesForCurrentOperatingSystem() -> [Patch] { 13 | if ProcessInfo.processInfo.isOperatingSystemAtLeast(OperatingSystemVersion(majorVersion: 10, minorVersion: 14, patchVersion: 4)) { 14 | return Patch.makePatchesForMacOS10_14_4() 15 | } else { 16 | return Patch.makePatchesForMacOS10_14() 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AirPlayEnabler/Code Injection/ExecutableInfo+ByteOrder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExecutableInfo+ByteOrder.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-14. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | import Darwin 10 | 11 | extension ExecutableInfo { 12 | var executableFileByteOrder: NXByteOrder { 13 | let hostByteOrder = NXHostByteOrder() 14 | 15 | if needsByteSwap { 16 | if hostByteOrder == NX_LittleEndian { 17 | return NX_BigEndian 18 | } else { 19 | return NX_LittleEndian 20 | } 21 | } else { 22 | return hostByteOrder 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /AirPlayEnabler/Code Injection/Low-Level Functions/ImageInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // ImageInfo.h 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-23. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | @import Darwin; 10 | @import Foundation; 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | struct ape_image_info { 15 | mach_vm_address_t header_address_in_task_space; 16 | }; 17 | 18 | kern_return_t ape_image_info_find(vm_map_t task_vm_map, 19 | mach_vm_address_t dyld_all_image_infos_address_in_task_space, 20 | const char *image_file_path, 21 | struct ape_image_info *image_info_out); 22 | 23 | NS_ASSUME_NONNULL_END 24 | -------------------------------------------------------------------------------- /AirPlayEnabler/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-11. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | import Dispatch 10 | import Foundation 11 | import os 12 | 13 | autoreleasepool { 14 | os_log("AirPlayEnabler has started.") 15 | 16 | let machServiceName = PrivilegedHelperInfo.shared.machServiceName 17 | let xpcListener = NSXPCListener(machServiceName: machServiceName) 18 | 19 | let xpcService = XPCService() 20 | xpcListener.delegate = xpcService 21 | 22 | DispatchQueue.main.async { 23 | OSInitiateActivity(named: "Initial Code Injection", flags: []) { 24 | try? CodeInjector.shared.injectCode() 25 | } 26 | 27 | os_log("Starting XPC listener for Mach service `%{public}@`.", 28 | machServiceName) 29 | xpcListener.resume() 30 | } 31 | 32 | dispatchMain() 33 | } 34 | -------------------------------------------------------------------------------- /AirPlayEnablerInterface/AirPlayEnablerInterfaceError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Errors.swift 3 | // AirPlayEnablerInterface 4 | // 5 | // Created by Darren Mo on 2018-12-18. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol AirPlayEnablerInterfaceError: Error, RawRepresentable where RawValue == Int { 12 | static var errorDomain: NSErrorDomain { get } 13 | } 14 | 15 | extension NSError { 16 | public convenience init(xpcServiceError: ErrorType) { 17 | self.init(domain: ErrorType.errorDomain as String, 18 | code: xpcServiceError.rawValue, 19 | userInfo: nil) 20 | } 21 | } 22 | 23 | extension AirPlayEnablerInterfaceError { 24 | public init?(nsError: NSError) { 25 | guard nsError.domain == Self.errorDomain as String else { 26 | return nil 27 | } 28 | self.init(rawValue: nsError.code) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /AirPlayEnabler/Extensions and Utilities/ActivityTracing.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ActivityTracing.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-25. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | func OSInitiateActivity(named description: String, 10 | flags: APEOSActivityFlag = [], 11 | activityBlock: () throws -> ReturnType) rethrows -> ReturnType { 12 | func rethrowsHelper(activityBlock: () throws -> ReturnType, 13 | rescue: ((Error) throws -> ReturnType)) rethrows -> ReturnType { 14 | var result: ReturnType? 15 | var error: Error? 16 | ape_os_activity_initiate(description, flags) { 17 | do { 18 | result = try activityBlock() 19 | } catch let activityBlockError { 20 | error = activityBlockError 21 | } 22 | } 23 | 24 | if let error = error { 25 | return try rescue(error) 26 | } else { 27 | return result! 28 | } 29 | } 30 | 31 | return try rethrowsHelper(activityBlock: activityBlock, rescue: { throw $0 }) 32 | } 33 | -------------------------------------------------------------------------------- /AirPlayEnabler/Code Injection/Low-Level Functions/Common.h: -------------------------------------------------------------------------------- 1 | // 2 | // Common.h 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-23. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | @import Darwin; 10 | @import Foundation; 11 | @import os.log; 12 | 13 | #define ENTER_FUNCTION() { \ 14 | os_log_debug(OS_LOG_DEFAULT, "Entering %s.", __FUNCTION__); \ 15 | } 16 | 17 | #define EXIT_FUNCTION(return_value) { \ 18 | os_log_debug(OS_LOG_DEFAULT, \ 19 | "Exiting %s with return value %d.", \ 20 | __FUNCTION__, \ 21 | (return_value)); \ 22 | return (return_value); \ 23 | } 24 | 25 | NS_ASSUME_NONNULL_BEGIN 26 | 27 | kern_return_t ape_cstring_create_from_task_vm(vm_map_t task_vm_map, 28 | mach_vm_address_t address_in_task_space, 29 | const char *_Nullable *_Nonnull cstring_out); 30 | 31 | void ape_cstring_free(const char *_Nullable *_Nonnull cstring_inout); 32 | 33 | NS_ASSUME_NONNULL_END 34 | -------------------------------------------------------------------------------- /AirPlayEnabler/Code Injection/Low-Level Functions/ExecutableInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // ExecutableInfo.h 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-12. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | @import Darwin; 10 | @import Foundation; 11 | @import MachO; 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | struct ape_executable_info { 16 | vm_map_t task_vm_map NS_SWIFT_NAME(taskVMMap); 17 | 18 | mach_vm_address_t header_address_in_task_space NS_SWIFT_NAME(headerAddressInTaskSpace); 19 | mach_vm_offset_t aslr_offset NS_SWIFT_NAME(aslrOffset); 20 | 21 | struct mach_header_64 header; 22 | bool needs_byte_swap NS_SWIFT_NAME(needsByteSwap); 23 | 24 | mach_vm_address_t dyld_all_image_infos_address_in_task_space NS_SWIFT_NAME(dyldAllImageInfosAddressInTaskSpace); 25 | } NS_SWIFT_NAME(ExecutableInfo); 26 | 27 | kern_return_t ape_executable_info_populate(vm_map_t task_vm_map, 28 | const char *executable_file_path, 29 | struct ape_executable_info *executable_info_out) NS_SWIFT_NAME(ExecutableInfo.populate(fromTaskVMDescribedBy:forExecutableFilePath:executableInfoOut:)); 30 | 31 | NS_ASSUME_NONNULL_END 32 | -------------------------------------------------------------------------------- /AirPlayEnabler/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | $(PRODUCT_BUNDLE_IDENTIFIER) 7 | CFBundleInfoDictionaryVersion 8 | 6.0 9 | CFBundleName 10 | $(TARGET_NAME) 11 | CFBundlePackageType 12 | APPL 13 | CFBundleShortVersionString 14 | 1.0.2 15 | CFBundleVersion 16 | 3 17 | LSMinimumSystemVersion 18 | $(MACOSX_DEPLOYMENT_TARGET) 19 | NSHumanReadableCopyright 20 | Copyright © 2018 Darren Mo. All rights reserved. 21 | SMAuthorizedClients 22 | 23 | anchor apple generic and identifier "mo.darren.optimus.player.mac" and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = PVLQ49LAH3) 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /AirPlayEnabler/Code Injection/InjectedCode+ExternalSymbolInfo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InjectedCode+ExternalSymbolInfo.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-25. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | import Darwin 10 | import Foundation 11 | 12 | extension InjectedCode { 13 | struct ExternalSymbolInfo { 14 | init(absoluteAddressRange: Range, 15 | replaceWithPointerValueAt externalSymbolPointerAddressInExecutableFile: mach_vm_address_t) { 16 | self.absoluteAddressRange = absoluteAddressRange 17 | self.externalSymbolPointerAddressInExecutableFile = externalSymbolPointerAddressInExecutableFile 18 | } 19 | 20 | let absoluteAddressRange: Range 21 | let externalSymbolPointerAddressInExecutableFile: mach_vm_address_t 22 | 23 | func externalSymbolPointerData(fromExecutableDescribedBy executableInfo: ExecutableInfo) throws -> Foundation.Data { 24 | let externalSymbolPointerAddressInTaskSpace = executableInfo.addressInTaskSpace(fromAddressInExecutableFile: externalSymbolPointerAddressInExecutableFile) 25 | 26 | guard let data = Foundation.Data(contentsOf: externalSymbolPointerAddressInTaskSpace, byteCount: mach_vm_size_t(absoluteAddressRange.count), inTaskVMDescribedBy: executableInfo.taskVMMap) else { 27 | throw DataCreationError.failedToResolveExternalSymbol 28 | } 29 | 30 | return data 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AirPlayEnabler/Code Injection/Patch+Requirement.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Patch+Requirement.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-21. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | import Darwin 10 | import Foundation 11 | 12 | extension Patch { 13 | struct Requirement { 14 | // MARK: - Initialization 15 | 16 | init(addressInExecutableFile: mach_vm_address_t, 17 | requiredMemoryData: MemoryData) { 18 | self.addressInExecutableFile = addressInExecutableFile 19 | self.requiredMemoryData = requiredMemoryData 20 | } 21 | 22 | // MARK: - Properties 23 | 24 | private let addressInExecutableFile: mach_vm_address_t 25 | private let requiredMemoryData: MemoryData 26 | 27 | // MARK: - Checking Satisfaction 28 | 29 | func isSatisfied(byExecutableDescribedBy executableInfo: ExecutableInfo) throws -> Bool { 30 | let addressInTaskSpace = executableInfo.addressInTaskSpace(fromAddressInExecutableFile: addressInExecutableFile) 31 | guard let taskData = Data(contentsOf: addressInTaskSpace, byteCount: mach_vm_size_t(requiredMemoryData.count), inTaskVMDescribedBy: executableInfo.taskVMMap) else { 32 | throw PatchError.failedToReadTargetProcessMemory 33 | } 34 | 35 | guard let requiredData = requiredMemoryData.data(in: executableInfo.executableFileByteOrder) else { 36 | throw PatchError.unsupportedTargetByteOrder 37 | } 38 | 39 | return taskData == requiredData 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /AirPlayEnabler/Extensions and Utilities/ActivityTracing.m: -------------------------------------------------------------------------------- 1 | // 2 | // ActivityTracing.m 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-12. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | #import "ActivityTracing.h" 10 | 11 | @import os.activity; 12 | @import os.lock; 13 | 14 | OS_ASSUME_NONNULL_BEGIN 15 | 16 | static const char *PermanentCStringFromNSString(NSString *nsString); 17 | 18 | void ape_os_activity_initiate(NSString *description, 19 | APEOSActivityFlag flags, 20 | os_block_t activity_block OS_NOESCAPE) { 21 | _os_activity_initiate(&__dso_handle, 22 | PermanentCStringFromNSString(description), 23 | (os_activity_flag_t)flags, 24 | activity_block); 25 | } 26 | 27 | static const char *PermanentCStringFromNSString(NSString *nsString) { 28 | static os_unfair_lock lock = OS_UNFAIR_LOCK_INIT; 29 | os_unfair_lock_lock(&lock); 30 | 31 | static NSMapTable *nsStringToCStringMap = nil; 32 | if (nsStringToCStringMap == nil) { 33 | nsStringToCStringMap = [[NSMapTable alloc] initWithKeyOptions:(NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPersonality) 34 | valueOptions:(NSPointerFunctionsMallocMemory | NSPointerFunctionsCStringPersonality | NSPointerFunctionsCopyIn) 35 | capacity:1]; 36 | } 37 | 38 | const char *cString = (__bridge void *)[nsStringToCStringMap objectForKey:nsString]; 39 | if (cString == NULL) { 40 | [nsStringToCStringMap setObject:(__bridge id)(void *)nsString.UTF8String forKey:[nsString copy]]; 41 | cString = (__bridge void *)[nsStringToCStringMap objectForKey:nsString]; 42 | } 43 | 44 | os_unfair_lock_unlock(&lock); 45 | 46 | return cString; 47 | } 48 | 49 | OS_ASSUME_NONNULL_END 50 | -------------------------------------------------------------------------------- /AirPlayEnabler/Code Injection/Data+TaskVM.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Data+TaskVM.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-24. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | import Darwin 10 | import Foundation 11 | 12 | extension Data { 13 | init?(contentsOf addressInTaskSpace: mach_vm_address_t, 14 | byteCount requestedBufferByteCount: mach_vm_size_t, 15 | inTaskVMDescribedBy taskVMMap: vm_map_t) { 16 | os_log(.info, 17 | "Reading task memory at address 0x%llx.", 18 | addressInTaskSpace) 19 | 20 | var bufferAddress: vm_offset_t = 0 21 | var bufferByteCount: mach_msg_type_number_t = 0 22 | let status = mach_vm_read(taskVMMap, 23 | addressInTaskSpace, 24 | requestedBufferByteCount, 25 | &bufferAddress, 26 | &bufferByteCount) 27 | if status != KERN_SUCCESS { 28 | os_log(.error, 29 | "mach_vm_read failed: %d.", 30 | status) 31 | return nil 32 | } else if bufferByteCount != requestedBufferByteCount { 33 | os_log(.error, 34 | "mach_vm_read returned size (%{iec-bytes}u) that is different from the requested size (%{iec-bytes}llu).", 35 | bufferByteCount, 36 | requestedBufferByteCount); 37 | return nil 38 | } 39 | 40 | guard let bufferPointer = UnsafeMutableRawPointer(bitPattern: bufferAddress) else { 41 | os_log(.fault, 42 | "mach_vm_read returned NULL pointer.") 43 | return nil 44 | } 45 | self.init(bytesNoCopy: bufferPointer, 46 | count: Int(bufferByteCount), 47 | deallocator: .virtualMemory) 48 | 49 | os_log(.info, 50 | "Task memory: %{public}@.", 51 | (self as NSData).description) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /AirPlayEnabler/Code Injection/InjectedCode+Data.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InjectedCode+Data.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-25. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension InjectedCode { 12 | struct Data { 13 | init(underlyingData: Foundation.Data, rangesToIgnore: [Range]) { 14 | self.underlyingData = underlyingData 15 | self.rangesToIgnore = rangesToIgnore.sorted { $0.startIndex < $1.startIndex } 16 | } 17 | 18 | private let underlyingData: Foundation.Data 19 | private let rangesToIgnore: [Range] 20 | 21 | var count: Int { 22 | return underlyingData.count 23 | } 24 | 25 | static func ==(lhs: Data, rhs: Foundation.Data) -> Bool { 26 | let count = lhs.underlyingData.count 27 | if count != rhs.count { 28 | return false 29 | } 30 | 31 | var lastIndex = 0 32 | for rangeToIgnore in lhs.rangesToIgnore { 33 | defer { 34 | lastIndex = rangeToIgnore.endIndex 35 | } 36 | 37 | if rangeToIgnore.startIndex <= lastIndex { 38 | continue 39 | } 40 | 41 | let rangeToCompare = lastIndex.. Bool { 58 | return rhs == lhs 59 | } 60 | 61 | func withUnsafeBytes(body: (UnsafePointer) throws -> ResultType) rethrows -> ResultType { 62 | return try underlyingData.withUnsafeBytes(body) 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /AirPlayEnabler/Code Injection/MemoryData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MemoryData.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-21. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct MemoryData: CustomStringConvertible { 12 | // MARK: - Initialization 13 | 14 | init(littleEndianData: Data) { 15 | self.littleEndianData = littleEndianData 16 | self.bigEndianData = nil 17 | self.count = littleEndianData.count 18 | } 19 | 20 | init(bigEndianData: Data) { 21 | self.littleEndianData = nil 22 | self.bigEndianData = bigEndianData 23 | self.count = bigEndianData.count 24 | } 25 | 26 | init(littleEndianData: Data, 27 | bigEndianData: Data) { 28 | let count = littleEndianData.count 29 | precondition(count == bigEndianData.count) 30 | 31 | self.littleEndianData = littleEndianData 32 | self.bigEndianData = bigEndianData 33 | self.count = count 34 | } 35 | 36 | // MARK: - Properties 37 | 38 | private let littleEndianData: Data? 39 | private let bigEndianData: Data? 40 | let count: Int 41 | 42 | // MARK: - Retrieving Data 43 | 44 | func data(in targetByteOrder: NXByteOrder) -> Data? { 45 | switch targetByteOrder { 46 | case NX_LittleEndian: 47 | guard let littleEndianData = littleEndianData else { 48 | return nil 49 | } 50 | return littleEndianData 51 | 52 | case NX_BigEndian: 53 | guard let bigEndianData = bigEndianData else { 54 | return nil 55 | } 56 | return bigEndianData 57 | 58 | default: 59 | return nil 60 | } 61 | } 62 | 63 | // MARK: - CustomStringConvertible Conformance 64 | 65 | var description: String { 66 | var components = [String]() 67 | 68 | if let littleEndianData = littleEndianData { 69 | components.append("littleEndianData: \((littleEndianData as NSData).description)") 70 | } 71 | if let bigEndianData = bigEndianData { 72 | components.append("bigEndianData: \((bigEndianData as NSData).description)") 73 | } 74 | 75 | return "MemoryData(\(components.joined(separator: ", ")))" 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /AirPlayEnablerInterface/AirPlayEnablerInterface.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AirPlayEnablerInterface.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-18. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | @objc 12 | public protocol AirPlayEnablerInterface { 13 | /** 14 | Checks whether the privileged helper is running. 15 | 16 | - Parameter reply: The XPC reply block. A call to this block indicates that the 17 | privileged helper is running. 18 | */ 19 | func isPrivilegedHelperRunning(withReply reply: @escaping () -> Void) 20 | 21 | /** 22 | Gets the privileged helper version. 23 | 24 | - Parameter reply: The XPC reply block. 25 | - Parameter version: The privileged helper version. 26 | */ 27 | func getPrivilegedHelperVersion(withReply reply: @escaping (_ version: PrivilegedHelperVersion) -> Void) 28 | 29 | /** 30 | Deletes the privileged helper files, removes the code injection, unregisters 31 | the privileged helper in launchd, and terminates the running process. 32 | 33 | After calling this function, wait for a connection interruption and then call 34 | `isPrivilegedHelperRunning(withReply:)` to confirm that the privileged helper has 35 | indeed been terminated. 36 | 37 | - Parameter reply: The XPC reply block. This will only be called if an error occurred; 38 | success means the privileged helper process has been terminated. 39 | - Parameter nsError: The error that occurred. Convert the error using 40 | `UninstallPrivilegedHelperError.init(nsError:)`. 41 | */ 42 | func uninstallPrivilegedHelper(withReply reply: @escaping (_ nsError: NSError) -> Void) 43 | } 44 | 45 | public enum UninstallPrivilegedHelperError: Int, AirPlayEnablerInterfaceError { 46 | public static let errorDomain: NSErrorDomain = "mo.darren.optimus.player.mac.airplay-enabler.uninstallPrivilegedHelper" 47 | 48 | case failedToReadLaunchdPlist 49 | case failedToDecodeLaunchdPlist 50 | case unsupportedLaunchdPlistProgramArguments 51 | case failedToFindProgramPathInLaunchdPlist 52 | case failedToDeleteLaunchdPlist 53 | case failedToDeleteProgram 54 | case failedToRemoveCodeInjection 55 | case failedToRunLaunchctlProcess 56 | case launchctlFailed 57 | case timedOutWaitingForLaunchdToKillPrivilegedHelper 58 | } 59 | -------------------------------------------------------------------------------- /AirPlayEnabler/Extensions and Utilities/PrivilegedHelperInfo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PrivilegedHelperInfo.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-18. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | import AirPlayEnablerInterface 10 | import Foundation 11 | 12 | struct PrivilegedHelperInfo { 13 | // MARK: - Initialization 14 | 15 | static let shared = PrivilegedHelperInfo() 16 | 17 | private init() { 18 | guard let infoDictionary = Bundle.main.infoDictionary else { 19 | preconditionFailure("Main bundle does not have info dictionary.") 20 | } 21 | 22 | let buildNumberKey = "CFBundleVersion" 23 | guard let buildNumberString = infoDictionary[buildNumberKey] as? String else { 24 | preconditionFailure("Valid `\(buildNumberKey)` property not found in main bundle info dictionary.") 25 | } 26 | 27 | let versionKey = "CFBundleShortVersionString" 28 | guard let versionString = infoDictionary[versionKey] as? String else { 29 | preconditionFailure("Valid `\(versionKey)` property not found in main bundle info dictionary.") 30 | } 31 | 32 | guard let version = PrivilegedHelperVersion(buildNumberString: buildNumberString, versionString: versionString) else { 33 | preconditionFailure("Build number string `\(buildNumberString)` and/or version string `\(versionString)` is invalid.") 34 | } 35 | 36 | // TODO: Extract the actual values from the embedded launchd plist to avoid 37 | // mismatches. 38 | guard let bundleIdentifier = Bundle.main.bundleIdentifier else { 39 | preconditionFailure("Main bundle does not have bundle identifier.") 40 | } 41 | 42 | let authorizedClientsKey = "SMAuthorizedClients" 43 | guard let clientCodeSigningRequirements = infoDictionary[authorizedClientsKey] as? [String] else { 44 | preconditionFailure("Valid `\(authorizedClientsKey)` property not found in main bundle info dictionary.") 45 | } 46 | 47 | self.version = version 48 | 49 | self.machServiceName = bundleIdentifier 50 | self.launchdLabel = bundleIdentifier 51 | self.helperName = bundleIdentifier 52 | 53 | self.clientCodeSigningRequirements = clientCodeSigningRequirements 54 | } 55 | 56 | // MARK: - Properties 57 | 58 | let version: PrivilegedHelperVersion 59 | 60 | let machServiceName: String 61 | let launchdLabel: String 62 | let helperName: String 63 | 64 | let clientCodeSigningRequirements: [String] 65 | } 66 | -------------------------------------------------------------------------------- /Injected Code/macOS 10.14/InjectedCode/Injection.c: -------------------------------------------------------------------------------- 1 | // 2 | // Injection.c 3 | // InjectedCode 4 | // 5 | // Created by Darren Mo on 2018-12-20. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | #include "Injection.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | __attribute__((__optnone__)) 17 | OSStatus OriginalFunction(SecStaticCodeRef staticCode, uint64_t arg1, bool *arg2, uint64_t arg3) { 18 | return errSecSuccess; 19 | } 20 | 21 | OSStatus RunInjectedCode(SecStaticCodeRef staticCode, uint64_t arg1, bool *arg2, uint64_t arg3) { 22 | static os_log_t log = NULL; 23 | static dispatch_once_t onceToken; 24 | dispatch_once(&onceToken, ^{ 25 | log = os_log_create("mo.darren.optimus.player.mac.airplay-enabler", "Injected Code"); 26 | }); 27 | 28 | os_log(log, "Starting to run injected code."); 29 | 30 | OSStatus status = errSecSuccess; 31 | 32 | CFStringRef requirementText = CFSTR("anchor apple generic and (certificate leaf[field.1.2.840.113635.100.6.1.9] or certificate 1[field.1.2.840.113635.100.6.2.6] and certificate leaf[field.1.2.840.113635.100.6.1.13] and certificate leaf[subject.OU] = PVLQ49LAH3)"); 33 | 34 | SecRequirementRef requirement = NULL; 35 | status = SecRequirementCreateWithString(requirementText, 36 | kSecCSDefaultFlags, 37 | &requirement); 38 | if (status != errSecSuccess) { 39 | os_log_error(log, 40 | "Failed to create requirement: %d.", 41 | status); 42 | goto originalCode; 43 | } 44 | 45 | status = SecStaticCodeCheckValidityWithErrors(staticCode, 46 | kSecCSDefaultFlags, 47 | requirement, 48 | NULL); 49 | CFRelease(requirement); 50 | if (status == errSecCSReqFailed) { 51 | os_log(log, "Code does not meet requirement."); 52 | goto originalCode; 53 | } else if (status != errSecSuccess) { 54 | os_log_error(log, 55 | "Failed to check whether code meets requirement: %d.", 56 | status); 57 | goto originalCode; 58 | } 59 | 60 | status = errSecSuccess; 61 | goto exit; 62 | 63 | originalCode: 64 | status = OriginalFunction(staticCode, arg1, arg2, arg3); 65 | 66 | exit: 67 | os_log(log, "Finished running injected code."); 68 | return status; 69 | } 70 | -------------------------------------------------------------------------------- /AirPlayEnabler/Extensions and Utilities/ActivityTracing.h: -------------------------------------------------------------------------------- 1 | // 2 | // ActivityTracing.h 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-12. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | @import os; 11 | 12 | OS_ASSUME_NONNULL_BEGIN 13 | 14 | /*! 15 | * @enum APEOSActivityFlag 16 | * 17 | * @discussion 18 | * Support flags for ape_os_activity_initiate. 19 | * 20 | * @constant APEOSActivityFlagDefault 21 | * Use the default flags. 22 | * 23 | * @constant APEOSActivityFlagDetached 24 | * Detach the newly created activity from the provided activity (if any). If 25 | * passed in conjunction with an exiting activity, the activity will only note 26 | * what activity "created" the new one, but will make the new activity a top 27 | * level activity. This allows users to see what activity triggered work 28 | * without actually relating the activities. 29 | * 30 | * @constant APEOSActivityFlagIfNonePresent 31 | * Will only create a new activity if none present. If an activity ID is 32 | * already present, a new object will be returned with the same activity ID 33 | * underneath. 34 | * 35 | * Passing both APEOSActivityFlagDetached and APEOSActivityFlagIfNonePresent 36 | * is undefined. 37 | */ 38 | typedef NS_OPTIONS(uint32_t, APEOSActivityFlag) { 39 | APEOSActivityFlagDefault = 0, 40 | APEOSActivityFlagDetached = 0x1, 41 | APEOSActivityFlagIfNonePresent = 0x2 42 | }; 43 | 44 | /*! 45 | * @function ape_os_activity_initiate 46 | * 47 | * @abstract 48 | * Synchronously initiates an activity using provided block. 49 | * 50 | * @discussion 51 | * Synchronously initiates an activity using the provided block and creates 52 | * a tracing buffer as appropriate. All new activities are created as a 53 | * subactivity of an existing activity on the current thread. 54 | * 55 | * 56 | * ape_os_activity_initiate("indexing database", APEOSActivityFlagDefault, ^(void) { 57 | * // either do work directly or issue work asynchronously 58 | * }); 59 | * 60 | * 61 | * @param description 62 | * A constant string describing the activity, e.g., "performClick" or 63 | * "menuSelection". 64 | * 65 | * @param flags 66 | * Flags to be used when initiating the activity, typically 67 | * OSActivityFlagDefault. 68 | * 69 | * @param activity_block 70 | * The block to execute a given activity 71 | */ 72 | OS_NOTHROW 73 | void ape_os_activity_initiate(NSString *description, 74 | APEOSActivityFlag flags, 75 | os_block_t activity_block OS_NOESCAPE); 76 | 77 | OS_ASSUME_NONNULL_END 78 | -------------------------------------------------------------------------------- /Injected Code/macOS 10.14/InjectedCode.xcodeproj/xcshareddata/xcschemes/InjectedCode.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /AirPlayEnabler/Code Injection/Low-Level Functions/Common.m: -------------------------------------------------------------------------------- 1 | // 2 | // Common.m 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-23. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | #import "Common.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | kern_return_t ape_cstring_create_from_task_vm(vm_map_t task_vm_map, 14 | mach_vm_address_t address_in_task_space, 15 | const char **cstring_out) { 16 | ENTER_FUNCTION(); 17 | 18 | if (cstring_out == NULL) { 19 | os_log_error(OS_LOG_DEFAULT, "cstring_out should not be NULL."); 20 | EXIT_FUNCTION(KERN_INVALID_ARGUMENT); 21 | } 22 | *cstring_out = NULL; 23 | 24 | mach_vm_size_t cstring_byte_count = 1; 25 | char *cstring = malloc(cstring_byte_count); 26 | if (cstring == NULL) { 27 | EXIT_FUNCTION(KERN_NO_SPACE); 28 | } 29 | 30 | // 128 was chosen by eyeballing the system framework names. 31 | // The longest file path seems to be 122 bytes: /System/Library/PrivateFrameworks/SpeechRecognitionCommandServices.framework/Versions/A/SpeechRecognitionCommandServices. 32 | mach_vm_size_t buffer_size = 128; 33 | char buffer[buffer_size]; 34 | 35 | mach_vm_address_t current_address_in_task_space = address_in_task_space; 36 | mach_vm_size_t max_bytes_to_read = buffer_size; 37 | while (true) { 38 | mach_vm_size_t bytes_read = 0; 39 | kern_return_t status = mach_vm_read_overwrite(task_vm_map, 40 | current_address_in_task_space, 41 | max_bytes_to_read, 42 | (mach_vm_address_t)buffer, 43 | &bytes_read); 44 | if (status == KERN_INVALID_ADDRESS) { 45 | max_bytes_to_read -= 1; 46 | if (max_bytes_to_read == 0) { 47 | break; 48 | } 49 | } else if (status != KERN_SUCCESS) { 50 | os_log_error(OS_LOG_DEFAULT, 51 | "mach_vm_read_overwrite failed: %d.", 52 | status); 53 | goto failure; 54 | } else if (bytes_read != max_bytes_to_read) { 55 | os_log_error(OS_LOG_DEFAULT, 56 | "mach_vm_read_overwrite returned size (%{iec-bytes}llu) that is different from the requested size (%{iec-bytes}llu).", 57 | bytes_read, 58 | max_bytes_to_read); 59 | goto failure; 60 | } 61 | 62 | bool did_find_null_terminator = false; 63 | mach_vm_size_t bytes_to_copy = 0; 64 | for (mach_vm_size_t idx = 0; idx < bytes_read; idx++) { 65 | if (buffer[idx] == '\0') { 66 | did_find_null_terminator = true; 67 | break; 68 | } 69 | 70 | bytes_to_copy += 1; 71 | } 72 | 73 | if (bytes_to_copy > 0) { 74 | mach_vm_size_t new_cstring_byte_count = cstring_byte_count + bytes_to_copy; 75 | 76 | char *new_cstring = realloc(cstring, new_cstring_byte_count); 77 | if (new_cstring == NULL) { 78 | free(cstring); 79 | EXIT_FUNCTION(KERN_NO_SPACE); 80 | } 81 | cstring = new_cstring; 82 | 83 | memcpy(cstring + cstring_byte_count - 1, buffer, bytes_to_copy); 84 | 85 | cstring_byte_count = new_cstring_byte_count; 86 | } 87 | 88 | if (did_find_null_terminator) { 89 | break; 90 | } 91 | 92 | current_address_in_task_space += bytes_read; 93 | } 94 | 95 | cstring[cstring_byte_count - 1] = '\0'; 96 | *cstring_out = cstring; 97 | 98 | EXIT_FUNCTION(KERN_SUCCESS); 99 | 100 | failure: 101 | free(cstring); 102 | EXIT_FUNCTION(KERN_FAILURE); 103 | } 104 | 105 | void ape_cstring_free(const char **cstring_inout) { 106 | if (cstring_inout != NULL) { 107 | free((void *)*cstring_inout); 108 | *cstring_inout = NULL; 109 | } 110 | } 111 | 112 | NS_ASSUME_NONNULL_END 113 | -------------------------------------------------------------------------------- /AirPlayEnabler/XPC Service/XPCService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // XPCService.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-17. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | import AirPlayEnablerInterface 10 | import Foundation 11 | import Security 12 | import os 13 | 14 | class XPCService: NSObject, NSXPCListenerDelegate { 15 | // MARK: - Initialization 16 | 17 | override init() { 18 | self.codeSigningRequirements = PrivilegedHelperInfo.shared.clientCodeSigningRequirements.map { requirementText in 19 | var requirement: SecRequirement! 20 | var unmanagedError: Unmanaged! 21 | let status = SecRequirementCreateWithStringAndErrors(requirementText as CFString, 22 | [], 23 | &unmanagedError, 24 | &requirement) 25 | if status != errSecSuccess { 26 | let error = unmanagedError.takeRetainedValue() 27 | preconditionFailure("Code signing requirement text, `\(requirementText)`, is not valid: \(error).") 28 | } 29 | 30 | return (requirement, requirementText) 31 | } 32 | 33 | super.init() 34 | } 35 | 36 | // MARK: - Properties 37 | 38 | private let codeSigningRequirements: [(SecRequirement, String)] 39 | private let serviceImplementation = XPCServiceImplementation() 40 | 41 | // MARK: - XPC Listener Delegate 42 | 43 | func listener(_ listener: NSXPCListener, 44 | shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool { 45 | // Note: Using the PID for authorization is racy because a new process could have replaced 46 | // the old process by the time we approve the XPC connection. However, in practice, this is 47 | // fine because if the old process was killed, the XPC connection would be closed. 48 | // 49 | // More info: https://forums.developer.apple.com/thread/72881#212532 50 | let clientPID = newConnection.processIdentifier 51 | 52 | os_log(.info, 53 | "Received connection request from process with PID %d.", 54 | clientPID) 55 | 56 | if !isClientAuthorized(clientPID) { 57 | return false 58 | } 59 | 60 | newConnection.exportedInterface = NSXPCInterface(with: AirPlayEnablerInterface.self) 61 | newConnection.exportedObject = serviceImplementation 62 | newConnection.resume() 63 | 64 | return true 65 | } 66 | 67 | // MARK: - Authorization 68 | 69 | private func isClientAuthorized(_ clientPID: pid_t) -> Bool { 70 | var clientCode: SecCode! 71 | let status = SecCodeCopyGuestWithAttributes(nil, 72 | [kSecGuestAttributePid: clientPID] as CFDictionary, 73 | [], 74 | &clientCode) 75 | if status != errSecSuccess { 76 | os_log(.error, 77 | "SecCodeCopyGuestWithAttributes for PID %d returned error status code: %d.", 78 | clientPID, 79 | status) 80 | return false 81 | } 82 | 83 | for (requirement, requirementText) in codeSigningRequirements { 84 | var unmanagedError: Unmanaged! 85 | let status = SecCodeCheckValidityWithErrors(clientCode, 86 | [], 87 | requirement, 88 | &unmanagedError) 89 | if status == errSecSuccess { 90 | return true 91 | } 92 | 93 | let error = unmanagedError.takeRetainedValue() 94 | os_log(.error, 95 | "SecCodeCheckValidityWithErrors for PID %d and requirement `%{public}@` returned error: %{public}@.", 96 | clientPID, 97 | requirementText, 98 | String(describing: error)) 99 | } 100 | 101 | return false 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Injected Code/macOS 10.14/Notes.txt: -------------------------------------------------------------------------------- 1 | amfid Capacity: 2 | 0x100007ae0 to 0x100007fff => 0x51F 3 | 4 | amfid Symbols: 5 | __NSConcreteGlobalBlock = 0x10000d1b8 (will be changed by dynamic linker) 6 | ___CFConstantStringClassReference = 0x10000d1c8 (will be changed by dynamic linker) 7 | ___stack_chk_guard = 0x100007038 8 | __stack_chk_fail = 0x100004f36 9 | os_log_create = 0x100004fc0 10 | os_log_type_enabled = 0x100004fc6 11 | _os_log_impl = 0x100004f48 12 | _os_log_error_impl = 0x100004f3c 13 | dispatch_once = 0x100004f6c 14 | SecRequirementCreateWithString = 0x100004f06 15 | SecStaticCodeCheckValidityWithErrors = 0x100004f12 16 | CFRelease = 0x100004e94 17 | OriginalFunction = 0x10000435f 18 | 19 | RunInjectedCode: 20 | 55 48 89 E5 41 57 41 56 41 55 41 54 53 48 83 EC 28 49 89 CF 49 89 D4 49 89 F5 48 89 7D C8 48 8B 05 83 05 00 00 48 8B 00 48 89 45 D0 48 83 3D 2C 06 00 00 FF 0F 85 22 02 00 00 48 8B 1D 17 06 00 00 31 F6 48 89 DF E8 7F 02 00 00 84 C0 74 34 49 89 E6 48 89 E0 4C 8D 40 F0 4C 89 C4 66 C7 40 F0 00 00 48 8D 3D 2F F5 FF FF 48 8D 0D F8 03 00 00 31 D2 41 B9 02 00 00 00 48 89 DE E8 38 02 00 00 4C 89 F4 48 8D 55 C0 48 C7 02 00 00 00 00 48 8D 3D A3 05 00 00 31 F6 E8 04 02 00 00 41 89 C6 45 85 F6 74 71 48 8B 1D AD 05 00 00 BE 10 00 00 00 48 89 DF E8 12 02 00 00 84 C0 0F 84 20 01 00 00 4C 89 6D B8 4D 89 E5 4D 89 FC 49 89 E7 48 89 E0 4C 8D 40 F0 4C 89 C4 C7 40 F0 00 01 00 04 44 89 70 F4 48 8D 3D AF F4 FF FF 48 8D 0D 98 03 00 00 BA 10 00 00 00 41 B9 08 00 00 00 48 89 DE E8 AF 01 00 00 4C 89 FC 4D 89 E7 4D 89 EC 4C 8B 6D B8 E9 CB 00 00 00 48 8B 55 C0 31 F6 31 C9 48 8B 7D C8 E8 80 01 00 00 89 C3 48 8B 7D C0 E8 69 01 00 00 85 DB 0F 84 B9 00 00 00 81 FB 16 FA FE FF 75 4C 48 8B 1D 10 05 00 00 31 F6 48 89 DF E8 78 01 00 00 84 C0 0F 84 86 00 00 00 49 89 E6 48 89 E0 4C 8D 40 F0 4C 89 C4 66 C7 40 F0 00 00 48 8D 3D 24 F4 FF FF 48 8D 0D 3D 03 00 00 31 D2 41 B9 02 00 00 00 48 89 DE E8 2D 01 00 00 EB 50 4C 8B 35 C4 04 00 00 BE 10 00 00 00 4C 89 F7 E8 29 01 00 00 84 C0 74 3B 4C 89 F6 49 89 E6 48 89 E0 4C 8D 40 F0 4C 89 C4 C7 40 F0 00 01 00 04 89 58 F4 48 8D 3D D2 F3 FF FF 48 8D 0D 0B 03 00 00 BA 10 00 00 00 41 B9 08 00 00 00 E8 D5 00 00 00 4C 89 F4 48 8B 7D C8 4C 89 EE 4C 89 E2 4C 89 F9 E8 F6 FD FF FF 48 8B 1D 5F 04 00 00 31 F6 48 89 DF E8 C7 00 00 00 84 C0 74 34 49 89 E6 48 89 E0 4C 8D 40 F0 4C 89 C4 66 C7 40 F0 00 00 48 8D 3D 77 F3 FF FF 48 8D 0D F0 02 00 00 31 D2 41 B9 02 00 00 00 48 89 DE E8 80 00 00 00 4C 89 F4 48 8B 05 66 03 00 00 48 8B 00 48 3B 45 D0 75 29 31 C0 48 8D 65 D8 5B 41 5C 41 5D 41 5E 41 5F 5D C3 48 8D 3D FD 03 00 00 48 8D 35 AE 03 00 00 E8 4F 00 00 00 E9 C6 FD FF FF E8 33 00 00 00 55 48 89 E5 48 8D 3D BC 00 00 00 48 8D 35 E2 00 00 00 E8 34 00 00 00 48 89 05 C1 03 00 00 5D C3 21 | 22 | __cstring/__oslogstring (shifted back 0xA1): 23 | 76 38 40 3F 30 00 6D 6F 2E 64 61 72 72 65 6E 2E 6F 70 74 69 6D 75 73 2E 70 6C 61 79 65 72 2E 6D 61 63 2E 61 69 72 70 6C 61 79 2D 65 6E 61 62 6C 65 72 00 49 6E 6A 65 63 74 65 64 20 43 6F 64 65 00 61 6E 63 68 6F 72 20 61 70 70 6C 65 20 67 65 6E 65 72 69 63 20 61 6E 64 20 28 63 65 72 74 69 66 69 63 61 74 65 20 6C 65 61 66 5B 66 69 65 6C 64 2E 31 2E 32 2E 38 34 30 2E 31 31 33 36 33 35 2E 31 30 30 2E 36 2E 31 2E 39 5D 20 6F 72 20 63 65 72 74 69 66 69 63 61 74 65 20 31 5B 66 69 65 6C 64 2E 31 2E 32 2E 38 34 30 2E 31 31 33 36 33 35 2E 31 30 30 2E 36 2E 32 2E 36 5D 20 61 6E 64 20 63 65 72 74 69 66 69 63 61 74 65 20 6C 65 61 66 5B 66 69 65 6C 64 2E 31 2E 32 2E 38 34 30 2E 31 31 33 36 33 35 2E 31 30 30 2E 36 2E 31 2E 31 33 5D 20 61 6E 64 20 63 65 72 74 69 66 69 63 61 74 65 20 6C 65 61 66 5B 73 75 62 6A 65 63 74 2E 4F 55 5D 20 3D 20 50 56 4C 51 34 39 4C 41 48 33 29 00 00 00 00 00 00 00 00 00 00 00 00 00 53 74 61 72 74 69 6E 67 20 74 6F 20 72 75 6E 20 69 6E 6A 65 63 74 65 64 20 63 6F 64 65 2E 00 00 46 61 69 6C 65 64 20 74 6F 20 63 72 65 61 74 65 20 72 65 71 75 69 72 65 6D 65 6E 74 3A 20 25 64 2E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 43 6F 64 65 20 64 6F 65 73 20 6E 6F 74 20 6D 65 65 74 20 72 65 71 75 69 72 65 6D 65 6E 74 2E 00 46 61 69 6C 65 64 20 74 6F 20 63 68 65 63 6B 20 77 68 65 74 68 65 72 20 63 6F 64 65 20 6D 65 65 74 73 20 72 65 71 75 69 72 65 6D 65 6E 74 3A 20 25 64 2E 00 00 00 00 00 00 00 00 00 00 00 00 00 46 69 6E 69 73 68 65 64 20 72 75 6E 6E 69 6E 67 20 69 6E 6A 65 63 74 65 64 20 63 6F 64 65 2E 00 24 | 25 | __const (shifted back 0x161): 26 | 00 00 00 00 00 00 00 00 20 00 00 00 00 00 00 00 A2 0D 00 00 01 00 00 00 00 00 00 00 00 00 00 00 18 80 00 00 01 00 00 00 00 00 00 50 00 00 00 00 E1 0C 00 00 01 00 00 00 60 10 00 00 01 00 00 00 27 | 28 | __cfstring/__bss (shifted back 0x160): 29 | 20 80 00 00 01 00 00 00 C8 07 00 00 00 00 00 00 E3 0D 00 00 01 00 00 00 E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -------------------------------------------------------------------------------- /AirPlayEnablerInterface/PrivilegedHelperVersion.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PrivilegedHelperVersion.swift 3 | // AirPlayEnablerInterface 4 | // 5 | // Created by Darren Mo on 2018-12-20. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public class PrivilegedHelperVersion: NSObject, NSSecureCoding, Comparable { 12 | // MARK: - Properties 13 | 14 | public let buildNumber: Int 15 | 16 | public let majorVersion: Int 17 | public let minorVersion: Int 18 | public let patchVersion: Int 19 | 20 | // MARK: - Initialization 21 | 22 | public init(buildNumber: Int, majorVersion: Int, minorVersion: Int, patchVersion: Int) { 23 | self.buildNumber = buildNumber 24 | self.majorVersion = majorVersion 25 | self.minorVersion = minorVersion 26 | self.patchVersion = patchVersion 27 | 28 | super.init() 29 | } 30 | 31 | public convenience init?(buildNumberString: String, versionString: String) { 32 | guard let buildNumber = Int(buildNumberString) else { 33 | return nil 34 | } 35 | 36 | let versionStringComponents = versionString.split(separator: ".") 37 | guard versionStringComponents.count == 3 else { 38 | return nil 39 | } 40 | 41 | guard let majorVersion = Int(versionStringComponents[0]) else { 42 | return nil 43 | } 44 | guard let minorVersion = Int(versionStringComponents[1]) else { 45 | return nil 46 | } 47 | guard let patchVersion = Int(versionStringComponents[2]) else { 48 | return nil 49 | } 50 | 51 | self.init(buildNumber: buildNumber, 52 | majorVersion: majorVersion, 53 | minorVersion: minorVersion, 54 | patchVersion: patchVersion) 55 | } 56 | 57 | // MARK: - NSSecureCoding Conformance 58 | 59 | public static let supportsSecureCoding = true 60 | 61 | private static let buildNumberCoderKey = "mo.darren.optimus.player.mac.airplay-enabler.PrivilegedHelperVersion.buildNumber" 62 | private static let majorVersionCoderKey = "mo.darren.optimus.player.mac.airplay-enabler.PrivilegedHelperVersion.majorVersion" 63 | private static let minorVersionCoderKey = "mo.darren.optimus.player.mac.airplay-enabler.PrivilegedHelperVersion.minorVersion" 64 | private static let patchVersionCoderKey = "mo.darren.optimus.player.mac.airplay-enabler.PrivilegedHelperVersion.patchVersion" 65 | 66 | public func encode(with aCoder: NSCoder) { 67 | aCoder.encode(buildNumber, forKey: PrivilegedHelperVersion.buildNumberCoderKey) 68 | aCoder.encode(majorVersion, forKey: PrivilegedHelperVersion.majorVersionCoderKey) 69 | aCoder.encode(minorVersion, forKey: PrivilegedHelperVersion.minorVersionCoderKey) 70 | aCoder.encode(patchVersion, forKey: PrivilegedHelperVersion.patchVersionCoderKey) 71 | } 72 | 73 | public required init?(coder aDecoder: NSCoder) { 74 | guard aDecoder.containsValue(forKey: PrivilegedHelperVersion.buildNumberCoderKey) else { 75 | return nil 76 | } 77 | guard aDecoder.containsValue(forKey: PrivilegedHelperVersion.majorVersionCoderKey) else { 78 | return nil 79 | } 80 | guard aDecoder.containsValue(forKey: PrivilegedHelperVersion.minorVersionCoderKey) else { 81 | return nil 82 | } 83 | guard aDecoder.containsValue(forKey: PrivilegedHelperVersion.patchVersionCoderKey) else { 84 | return nil 85 | } 86 | 87 | self.buildNumber = aDecoder.decodeInteger(forKey: PrivilegedHelperVersion.buildNumberCoderKey) 88 | self.majorVersion = aDecoder.decodeInteger(forKey: PrivilegedHelperVersion.majorVersionCoderKey) 89 | self.minorVersion = aDecoder.decodeInteger(forKey: PrivilegedHelperVersion.minorVersionCoderKey) 90 | self.patchVersion = aDecoder.decodeInteger(forKey: PrivilegedHelperVersion.patchVersionCoderKey) 91 | } 92 | 93 | // MARK: - Comparable Conformance 94 | 95 | public static func <(lhs: PrivilegedHelperVersion, rhs: PrivilegedHelperVersion) -> Bool { 96 | return lhs.buildNumber < rhs.buildNumber 97 | } 98 | 99 | // MARK: - Hashable Conformance 100 | 101 | public override var hash: Int { 102 | return buildNumber.hashValue 103 | } 104 | 105 | // MARK: - Equatable Conformance 106 | 107 | public override func isEqual(_ object: Any?) -> Bool { 108 | guard let other = object as? PrivilegedHelperVersion else { 109 | return false 110 | } 111 | 112 | return self.buildNumber == other.buildNumber 113 | } 114 | 115 | public static func isMarketingVersionEqual(_ lhs: PrivilegedHelperVersion, 116 | _ rhs: PrivilegedHelperVersion) -> Bool { 117 | return 118 | lhs.majorVersion == rhs.majorVersion && 119 | lhs.minorVersion == rhs.minorVersion && 120 | lhs.patchVersion == rhs.patchVersion 121 | } 122 | 123 | // MARK: - CustomStringConvertible Conformance 124 | 125 | public override var description: String { 126 | return description(includingBuildNumber: true) 127 | } 128 | 129 | public var marketingDescription: String { 130 | return description(includingBuildNumber: false) 131 | } 132 | 133 | public func description(includingBuildNumber shouldIncludeBuildNumber: Bool) -> String { 134 | var description = "\(majorVersion).\(minorVersion).\(patchVersion)" 135 | 136 | if shouldIncludeBuildNumber { 137 | description += " (\(buildNumber))" 138 | } 139 | 140 | return description 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Optimus Player AirPlay Enabler 2 | 3 | A helper tool that enables [Optimus Player](https://www.optimusplayer.com/) to stream audio using AirPlay 2. 4 | 5 | Update: No longer needed on macOS Catalina or later. 6 | 7 | ## License 8 | 9 | Copyright © 2018–2019 Darren Mo. All rights reserved. 10 | 11 | This source code is provided to you for **viewing purposes only**. If you would like additional rights, then send an email to [contact@optimusplayer.com](mailto:contact@optimusplayer.com?subject=AirPlay%20Enabler:%20fill_this_in) describing your use case. 12 | 13 | ## Background 14 | 15 | AirPlay 2 is the second version of the proprietary AirPlay streaming media protocol used by Apple devices. AirPlay 2 focuses on audio, featuring enhanced buffering, stereo pairs, and multi-room audio. 16 | 17 | The first version of AirPlay was implemented at the system level, requiring no changes from developers (aside from synchronization with video). However, AirPlay 2 must be integrated at the app level. 18 | 19 | On iOS and tvOS, apps use [`AVRoutePickerView`](https://developer.apple.com/documentation/avkit/avroutepickerview) to route audio to AirPlay 2 output devices. This API also exists on macOS (not public yet), but is missing a core component, rendering it unusable. 20 | 21 | As of macOS 10.14.6, no apps aside from iTunes have been able to use AirPlay 2. Until now. 22 | 23 | ## Problem 24 | 25 | The core (private) APIs for using AirPlay 2 are inside the `AVFoundation` framework. The `AVFoundation` functions wrap lower-level `CoreMedia` functions (and others). 26 | 27 | The complicating piece of the puzzle is an [XPC](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingXPCServices.html#//apple_ref/doc/uid/10000172i-SW6-SW1) service called `AirPlayXPCHelper`. This service simply wraps `CoreMedia` functionality; its main purpose is to use the XPC mechanism to require special privileges from clients who wish to use two key APIs related to AirPlay: discovering output devices and routing to output devices. (The reason for this requirement is unclear to me.) 28 | 29 | `AirPlayXPCHelper` requires the `com.apple.avfoundation.allows-access-to-device-list` [entitlement](https://developer.apple.com/documentation/bundleresources/entitlements) to discover output devices and the `com.apple.avfoundation.allows-set-output-device` entitlement to route to output devices. Only Apple-provisioned executables can have these restricted entitlements. This is the problem that the helper tool addresses. 30 | 31 | ## Design 32 | 33 | ### Overview 34 | 35 | Restricted entitlements are validated by the `amfid` system process when an executable is launched. The helper tool injects code into `amfid` to bypass this validation when launching Optimus Player executables, thus allowing Optimus Player executables to obtain the privileges needed to use the AirPlay 2 private APIs. 36 | 37 | ### Goals 38 | 39 | - To enable Optimus Player to use AirPlay 2. 40 | - To minimize side effects on the system and on other apps. 41 | - To be low-maintenance. 42 | - To be easily removable. 43 | 44 | ### Specific Requirements 45 | 46 | - The helper tool should be able to inject code into the `amfid` system process. 47 | - The code injection should only proceed if the relevant sections of the original `amfid` code are exactly as expected. (The `amfid` code may change due to operating system updates.) 48 | - The injection of code should be as atomic as possible; if an operation fails, the injector should roll back previous operations. 49 | - The injected code should only bypass the restricted entitlements validation for Optimus Player executables; other executables should still be validated normally. 50 | - The helper tool should run automatically, requiring no action from the user after installation (aside from updates to the helper tool). 51 | - The code injection should be removed automatically during uninstallation. 52 | 53 | ### Solution 54 | 55 | #### Privileged Helper Tool 56 | 57 | The helper tool is implemented as a [Launch Daemon](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/DesigningDaemons.html#//apple_ref/doc/uid/10000172i-SW4-SW5), which gives it the following features: 58 | 59 | - runs with `root` user permissions, which is needed to inject code into the `amfid` system process; 60 | - launches automatically at system startup; 61 | - re-launches when killed; and 62 | - integrates with XPC. 63 | 64 | When the helper tool is launched, it first runs the code injector and then starts the XPC service. 65 | 66 | #### XPC Service 67 | 68 | One component of the helper tool is the XPC service. The XPC service allows Optimus Player to get the version of the helper tool to check for updates and to uninstall the helper tool. 69 | 70 | The uninstallation is performed by the helper tool itself (which is already running with `root` user permissions) to avoid an unnecessary authorization request. 71 | 72 | The helper tool only allows requests from Optimus Player executables. 73 | 74 | #### Code Injector 75 | 76 | The code injector modifies the running `amfid` process but does not modify the file system. This approach is required because the `amfid` executable must have a valid Apple code signature in order to be launched. 77 | 78 | The code injector first finds the `amfid` process and then analyzes its memory structure to find the memory location of the executable image. Once the executable image has been found, code can be injected into the executable. 79 | 80 | The procedure for injecting code: 81 | 82 | 1. Get the patches (“patch” described below) that are compatible with the current operating system version. 83 | 2. Suspend the `amfid` process to prevent the memory from changing. (The memory can still change if there is another code injector running at the same time, but there is nothing we can do about that.) 84 | 3. Apply the patches. 85 | 4. If a patch fails to be applied, roll back the already-applied patches. 86 | 87 | A patch consists mainly of the following properties: 88 | 89 | - address in the executable 90 | - requirements 91 | - address in the executable 92 | - required data 93 | - target data 94 | - replacement data 95 | 96 | (There are some extra details for handling external symbols and other problems; read the code if you wish to learn more.) 97 | 98 | The procedure for removing the code injection is similar. 99 | 100 | #### Injected Code 101 | 102 | There is a function in the original `amfid` code that checks whether an executable is allowed to have restricted entitlements. The helper tool replaces the call to that function with a call to an injected function. 103 | 104 | The injected function checks whether the executable being evaluated is an Optimus Player executable. If it is, then the injected function returns a status value indicating success. If the executable is not an Optimus Player executable or if an error occurred while checking, then the injected function calls the original function and returns its status value. 105 | -------------------------------------------------------------------------------- /AirPlayEnabler/Code Injection/InjectedCode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InjectedCode.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-25. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | import Darwin 10 | import Foundation 11 | 12 | struct InjectedCode { 13 | // MARK: - Initialization 14 | 15 | init(memoryData: MemoryData, 16 | absoluteAddressRanges: [Range] = [], 17 | externalSymbolInfos: [ExternalSymbolInfo] = [], 18 | writableRanges: [Range] = []) { 19 | let count = memoryData.count 20 | precondition(InjectedCode.areRangesValid(absoluteAddressRanges, 21 | forDataCount: count, 22 | isAddress: true)) 23 | precondition(InjectedCode.areExternalSymbolInfosValid(externalSymbolInfos, 24 | forDataCount: count)) 25 | precondition(InjectedCode.areRangesValid(writableRanges, 26 | forDataCount: count, 27 | isAddress: false)) 28 | 29 | self.memoryData = memoryData 30 | self.count = count 31 | 32 | self.absoluteAddressRanges = absoluteAddressRanges 33 | self.externalSymbolInfos = externalSymbolInfos 34 | self.writableRanges = writableRanges 35 | } 36 | 37 | private static func areExternalSymbolInfosValid(_ externalSymbolInfos: [ExternalSymbolInfo], 38 | forDataCount dataCount: Int) -> Bool { 39 | return areRangesValid(externalSymbolInfos.map { $0.absoluteAddressRange }, 40 | forDataCount: dataCount, 41 | isAddress: true) 42 | } 43 | 44 | private static func areRangesValid(_ ranges: [Range], 45 | forDataCount dataCount: Int, 46 | isAddress: Bool) -> Bool { 47 | if !ranges.allSatisfy({ isRangeValid($0, forDataCount: dataCount, isAddress: isAddress) }) { 48 | return false 49 | } 50 | 51 | if ranges.count > 1 { 52 | let ranges = ranges.sorted { $0.startIndex < $1.startIndex } 53 | for (idx, lhsRange) in ranges.dropLast().enumerated() { 54 | let rhsRange = ranges[idx + 1] 55 | if lhsRange.overlaps(rhsRange) { 56 | return false 57 | } 58 | } 59 | } 60 | 61 | return true 62 | } 63 | 64 | private static func isRangeValid(_ range: Range, 65 | forDataCount dataCount: Int, 66 | isAddress: Bool) -> Bool { 67 | if range.startIndex < 0 || range.endIndex > dataCount { 68 | return false 69 | } 70 | 71 | if isAddress { 72 | if range.count != 8 { // 64-bit 73 | return false 74 | } 75 | } 76 | 77 | return true 78 | } 79 | 80 | // MARK: - Properties 81 | 82 | private let memoryData: MemoryData 83 | let count: Int 84 | 85 | private let absoluteAddressRanges: [Range] 86 | private let externalSymbolInfos: [ExternalSymbolInfo] 87 | private let writableRanges: [Range] 88 | 89 | // MARK: - Making Data 90 | 91 | enum DataCreationError: Error { 92 | case unsupportedTargetByteOrder 93 | case failedToResolveExternalSymbol 94 | } 95 | 96 | func makeData(forExecutableDescribedBy executableInfo: ExecutableInfo) throws -> Data { 97 | let executableFileByteOrder = executableInfo.executableFileByteOrder 98 | guard var data = memoryData.data(in: executableFileByteOrder) else { 99 | throw DataCreationError.unsupportedTargetByteOrder 100 | } 101 | 102 | let aslrOffset = executableInfo.aslrOffset 103 | 104 | for range in absoluteAddressRanges { 105 | var addressData = data[range] 106 | 107 | let addressSizeInBytes = range.count 108 | switch addressSizeInBytes { 109 | case 8: // 64-bit 110 | UInt64.apply(aslrOffset: aslrOffset, 111 | to: &addressData, 112 | addressDataByteOrder: executableFileByteOrder) 113 | 114 | default: 115 | preconditionFailure("Unsupported absolute address size: \(addressSizeInBytes) bytes.") 116 | } 117 | 118 | data[range] = addressData 119 | } 120 | 121 | for externalSymbolInfo in externalSymbolInfos { 122 | let absoluteAddressRange = externalSymbolInfo.absoluteAddressRange 123 | 124 | let currentAbsoluteAddressData = data[absoluteAddressRange] 125 | let newAbsoluteAddressData = try externalSymbolInfo.externalSymbolPointerData(fromExecutableDescribedBy: executableInfo) 126 | 127 | let addressSizeInBytes = absoluteAddressRange.count 128 | switch addressSizeInBytes { 129 | case 8: // 64-bit 130 | os_log(.debug, 131 | "Replacing absolute address 0x%llx with resolved external symbol absolute address 0x%llx.", 132 | UInt64(source: currentAbsoluteAddressData, 133 | sourceByteOrder: executableFileByteOrder), 134 | UInt64(source: newAbsoluteAddressData, 135 | sourceByteOrder: executableFileByteOrder)) 136 | 137 | default: 138 | preconditionFailure("Unsupported absolute address size: \(addressSizeInBytes) bytes.") 139 | } 140 | 141 | data[absoluteAddressRange] = newAbsoluteAddressData 142 | } 143 | 144 | return Data(underlyingData: data, 145 | rangesToIgnore: writableRanges) 146 | } 147 | } 148 | 149 | // MARK: - 150 | 151 | fileprivate extension FixedWidthInteger where Self: UnsignedInteger { 152 | init(source data: Data, sourceByteOrder: NXByteOrder) { 153 | var source: Self = 0 154 | data.withUnsafeBytes { (pointer: UnsafePointer) in 155 | source = pointer.pointee 156 | } 157 | 158 | let needsByteSwap = NXHostByteOrder() != sourceByteOrder 159 | if needsByteSwap { 160 | self = source.byteSwapped 161 | } else { 162 | self = source 163 | } 164 | } 165 | 166 | static func apply(aslrOffset: mach_vm_offset_t, 167 | to addressData: inout Data, 168 | addressDataByteOrder: NXByteOrder) { 169 | addressData.withUnsafeMutableBytes { (addressPointer: UnsafeMutablePointer) in 170 | let needsByteSwap = NXHostByteOrder() != addressDataByteOrder 171 | 172 | var address: Self 173 | if needsByteSwap { 174 | address = addressPointer.pointee.byteSwapped 175 | } else { 176 | address = addressPointer.pointee 177 | } 178 | 179 | let originalAddress = address 180 | address += Self(aslrOffset) 181 | 182 | os_log(.debug, 183 | "Applying ASLR offset 0x%llx to absolute address 0x%llx, which produces address 0x%llx.", 184 | aslrOffset, 185 | UInt64(originalAddress), 186 | UInt64(address)) 187 | 188 | if needsByteSwap { 189 | addressPointer.pointee = address.byteSwapped 190 | } else { 191 | addressPointer.pointee = address 192 | } 193 | } 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /AirPlayEnabler/Code Injection/Low-Level Functions/ImageInfo.m: -------------------------------------------------------------------------------- 1 | // 2 | // ImageInfo.m 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-23. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | // Inspired by rodionovd: https://github.com/rodionovd/liblorgnette/blob/master/lorgnette.c 9 | // 10 | 11 | #import "ImageInfo.h" 12 | 13 | @import os.log; 14 | 15 | #import 16 | 17 | #import "Common.h" 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | // MARK: - Structs 22 | 23 | // Compatible with the 64-bit version of the dyld_all_image_infos struct. 24 | struct ape_dyld_all_image_infos { 25 | uint32_t version; 26 | 27 | uint32_t image_info_count; 28 | mach_vm_address_t image_infos_address_in_task_space; 29 | 30 | // Unused fields are omitted. 31 | }; 32 | 33 | // Compatible with the 64-bit version of the dyld_image_info struct. 34 | struct ape_dyld_image_info { 35 | mach_vm_address_t header_address_in_task_space; 36 | mach_vm_address_t file_path_address_in_task_space; 37 | 38 | // Unused fields are omitted. 39 | }; 40 | 41 | // MARK: - Static Function Declarations 42 | 43 | static bool dyld_needs_swap(uint32_t dyld_all_image_infos_version); 44 | static void swap_dyld_all_image_infos(struct ape_dyld_all_image_infos *dyld_all_image_infos_inout); 45 | static void swap_dyld_image_info(struct ape_dyld_image_info *dyld_image_info_inout); 46 | 47 | // MARK: - Function Definitions 48 | 49 | kern_return_t ape_image_info_find(vm_map_t task_vm_map, 50 | mach_vm_address_t dyld_all_image_infos_address_in_task_space, 51 | const char *image_file_path, 52 | struct ape_image_info *image_info_out) { 53 | ENTER_FUNCTION(); 54 | 55 | if (image_file_path == NULL) { 56 | os_log_error(OS_LOG_DEFAULT, "image_file_path should not be NULL."); 57 | EXIT_FUNCTION(KERN_INVALID_ARGUMENT); 58 | } 59 | if (image_info_out == NULL) { 60 | os_log_error(OS_LOG_DEFAULT, "image_info_out should not be NULL."); 61 | EXIT_FUNCTION(KERN_INVALID_ARGUMENT); 62 | } 63 | 64 | struct ape_dyld_all_image_infos dyld_all_image_infos = {0}; 65 | mach_vm_size_t requested_dyld_all_image_infos_size = sizeof(dyld_all_image_infos); 66 | mach_vm_size_t dyld_all_image_infos_size = 0; 67 | kern_return_t status = mach_vm_read_overwrite(task_vm_map, 68 | dyld_all_image_infos_address_in_task_space, 69 | requested_dyld_all_image_infos_size, 70 | (mach_vm_address_t)&dyld_all_image_infos, 71 | &dyld_all_image_infos_size); 72 | if (status != KERN_SUCCESS) { 73 | os_log_error(OS_LOG_DEFAULT, 74 | "mach_vm_read_overwrite failed: %d.", 75 | status); 76 | EXIT_FUNCTION(KERN_FAILURE); 77 | } else if (dyld_all_image_infos_size != requested_dyld_all_image_infos_size) { 78 | os_log_error(OS_LOG_DEFAULT, 79 | "mach_vm_read_overwrite returned size (%{iec-bytes}llu) that is different from the requested size (%{iec-bytes}llu).", 80 | dyld_all_image_infos_size, 81 | requested_dyld_all_image_infos_size); 82 | EXIT_FUNCTION(KERN_FAILURE); 83 | } 84 | 85 | bool needs_swap = dyld_needs_swap(dyld_all_image_infos.version); 86 | if (needs_swap) { 87 | swap_dyld_all_image_infos(&dyld_all_image_infos); 88 | } 89 | 90 | uint32_t image_info_count = dyld_all_image_infos.image_info_count; 91 | mach_vm_address_t current_address_in_task_space = dyld_all_image_infos.image_infos_address_in_task_space; 92 | for (uint32_t idx = 0; idx < image_info_count; idx++) { 93 | struct ape_dyld_image_info dyld_image_info = {0}; 94 | mach_vm_size_t requested_dyld_image_info_size = sizeof(dyld_image_info); 95 | mach_vm_size_t dyld_image_info_size = 0; 96 | kern_return_t status = mach_vm_read_overwrite(task_vm_map, 97 | current_address_in_task_space, 98 | requested_dyld_image_info_size, 99 | (mach_vm_address_t)&dyld_image_info, 100 | &dyld_image_info_size); 101 | if (status != KERN_SUCCESS) { 102 | os_log_error(OS_LOG_DEFAULT, 103 | "mach_vm_read_overwrite failed: %d.", 104 | status); 105 | EXIT_FUNCTION(KERN_FAILURE); 106 | } else if (dyld_image_info_size != requested_dyld_image_info_size) { 107 | os_log_error(OS_LOG_DEFAULT, 108 | "mach_vm_read_overwrite returned size (%{iec-bytes}llu) that is different from the requested size (%{iec-bytes}llu).", 109 | dyld_image_info_size, 110 | requested_dyld_image_info_size); 111 | EXIT_FUNCTION(KERN_FAILURE); 112 | } 113 | 114 | if (needs_swap) { 115 | swap_dyld_image_info(&dyld_image_info); 116 | } 117 | 118 | const char *image_file_path_from_dyld = NULL; 119 | status = ape_cstring_create_from_task_vm(task_vm_map, 120 | dyld_image_info.file_path_address_in_task_space, 121 | &image_file_path_from_dyld); 122 | if (status != KERN_SUCCESS) { 123 | os_log_error(OS_LOG_DEFAULT, 124 | "ape_cstring_create_from_task_vm failed: %d.", 125 | status); 126 | EXIT_FUNCTION(KERN_FAILURE); 127 | } 128 | 129 | int compare_result = strcmp(image_file_path_from_dyld, image_file_path); 130 | free((void *)image_file_path_from_dyld); 131 | 132 | if (compare_result == 0) { 133 | os_log(OS_LOG_DEFAULT, 134 | "Found image for `%{public}s` at 0x%llx (in task space).", 135 | image_file_path_from_dyld, 136 | dyld_image_info.header_address_in_task_space); 137 | 138 | struct ape_image_info image_info = { 139 | .header_address_in_task_space = dyld_image_info.header_address_in_task_space 140 | }; 141 | *image_info_out = image_info; 142 | 143 | break; 144 | } 145 | 146 | // ape_dyld_image_info is only a subset of dyld_image_info, so we need to use 147 | // the size of the latter struct to advance the address. 148 | current_address_in_task_space += sizeof(struct dyld_image_info); 149 | } 150 | 151 | EXIT_FUNCTION(KERN_SUCCESS); 152 | } 153 | 154 | static bool dyld_needs_swap(uint32_t dyld_all_image_infos_version) { 155 | // From the LLVM source code: 156 | // > If anything in the high byte is set, we probably got the byte order incorrect. 157 | if ((dyld_all_image_infos_version & 0xff000000) != 0) { 158 | return true; 159 | } 160 | 161 | return false; 162 | } 163 | 164 | static void swap_dyld_all_image_infos(struct ape_dyld_all_image_infos *dyld_all_image_infos_inout) { 165 | dyld_all_image_infos_inout->version = _OSSwapInt32(dyld_all_image_infos_inout->version); 166 | dyld_all_image_infos_inout->image_info_count = _OSSwapInt32(dyld_all_image_infos_inout->image_info_count); 167 | dyld_all_image_infos_inout->image_infos_address_in_task_space = _OSSwapInt64(dyld_all_image_infos_inout->image_infos_address_in_task_space); 168 | } 169 | 170 | static void swap_dyld_image_info(struct ape_dyld_image_info *dyld_image_info_inout) { 171 | dyld_image_info_inout->header_address_in_task_space = _OSSwapInt64(dyld_image_info_inout->header_address_in_task_space); 172 | dyld_image_info_inout->file_path_address_in_task_space = _OSSwapInt64(dyld_image_info_inout->file_path_address_in_task_space); 173 | } 174 | 175 | NS_ASSUME_NONNULL_END 176 | -------------------------------------------------------------------------------- /AirPlayEnabler/XPC Service/XPCServiceImplementation+UninstallPrivilegedHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // XPCServiceImplementation+UninstallPrivilegedHelper.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-18. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | import AirPlayEnablerInterface 10 | import Foundation 11 | import os 12 | 13 | extension XPCServiceImplementation { 14 | func uninstallPrivilegedHelper(withReply reply: @escaping (NSError) -> Void) { 15 | OSInitiateActivity(named: "\(type(of: self)).\(#function)") { 16 | _uninstallPrivilegedHelper(withReply: reply) 17 | } 18 | } 19 | 20 | private func _uninstallPrivilegedHelper(withReply reply: @escaping (NSError) -> Void) { 21 | let launchdPlistPath = "/Library/LaunchDaemons/\(PrivilegedHelperInfo.shared.helperName).plist" 22 | 23 | do { 24 | let launchdPlist = try LaunchdPlist(contentsOf: launchdPlistPath) 25 | let programPath = try launchdPlist.determineProgramPath() 26 | 27 | try XPCServiceImplementation.deleteLaunchdPlist(at: launchdPlistPath) 28 | try XPCServiceImplementation.deleteProgram(at: programPath) 29 | try XPCServiceImplementation.removeCodeInjection() 30 | try XPCServiceImplementation.unregisterPrivilegedHelperInLaunchd() 31 | } catch let error as UninstallPrivilegedHelperError { 32 | let nsError = NSError(xpcServiceError: error) 33 | reply(nsError) 34 | } catch { 35 | fatalError("Caught error that is not of type `UninstallPrivilegedHelperError`: \(error).") 36 | } 37 | } 38 | 39 | private struct LaunchdPlist: Decodable { 40 | let programAbsolutePath: String? 41 | let programArguments: [String]? 42 | 43 | enum CodingKeys: String, CodingKey { 44 | case programAbsolutePath = "Program" 45 | case programArguments = "ProgramArguments" 46 | } 47 | 48 | init(contentsOf launchdPlistPath: String) throws { 49 | let launchdPlistData: Data 50 | do { 51 | launchdPlistData = try Data(contentsOf: URL(fileURLWithPath: launchdPlistPath)) 52 | } catch { 53 | os_log(.fault, 54 | "Failed to read `%{public}@`: %{public}@.", 55 | launchdPlistPath, 56 | String(describing: error)) 57 | throw UninstallPrivilegedHelperError.failedToReadLaunchdPlist 58 | } 59 | 60 | let propertyListDecoder = PropertyListDecoder() 61 | do { 62 | self = try propertyListDecoder.decode(type(of: self), 63 | from: launchdPlistData) 64 | } catch { 65 | os_log(.fault, 66 | "Failed to decode contents of `%{public}@`: %{public}@.", 67 | launchdPlistPath, 68 | String(describing: error)) 69 | throw UninstallPrivilegedHelperError.failedToDecodeLaunchdPlist 70 | } 71 | } 72 | 73 | func determineProgramPath() throws -> String { 74 | if let programAbsolutePath = programAbsolutePath { 75 | return programAbsolutePath 76 | } else if let programArguments = programArguments, !programArguments.isEmpty { 77 | let programPath = programArguments[0] 78 | guard (programPath as NSString).isAbsolutePath else { 79 | os_log(.error, 80 | "The first argument of the `ProgramArguments` property (in the launchd plist) is a relative path, which we do not support: `%{public}@`.", 81 | programPath) 82 | throw UninstallPrivilegedHelperError.unsupportedLaunchdPlistProgramArguments 83 | } 84 | 85 | return programPath 86 | } else { 87 | os_log(.fault, 88 | "The launchd plist does not contain the path to the program.") 89 | throw UninstallPrivilegedHelperError.failedToFindProgramPathInLaunchdPlist 90 | } 91 | } 92 | } 93 | 94 | private static func deleteLaunchdPlist(at launchdPlistPath: String) throws { 95 | do { 96 | try FileManager.default.removeItem(at: URL(fileURLWithPath: launchdPlistPath)) 97 | } catch { 98 | os_log(.fault, 99 | "Failed to delete `%{public}@`: %{public}@.", 100 | launchdPlistPath, 101 | String(describing: error)) 102 | throw UninstallPrivilegedHelperError.failedToDeleteLaunchdPlist 103 | } 104 | 105 | os_log("Deleted `%{public}@`.", 106 | launchdPlistPath) 107 | } 108 | 109 | private static func deleteProgram(at programPath: String) throws { 110 | do { 111 | try FileManager.default.removeItem(at: URL(fileURLWithPath: programPath)) 112 | } catch { 113 | os_log(.fault, 114 | "Failed to delete `%{public}@`: %{public}@.", 115 | programPath, 116 | String(describing: error)) 117 | throw UninstallPrivilegedHelperError.failedToDeleteProgram 118 | } 119 | 120 | os_log("Deleted `%{public}@`.", 121 | programPath) 122 | } 123 | 124 | private static func removeCodeInjection() throws { 125 | do { 126 | try CodeInjector.shared.removeCodeInjection() 127 | } catch CodeInjector.InjectError.failedToAttachToTargetProcess { 128 | os_log(.error, 129 | """ 130 | Failed to attach to the target process. \ 131 | This is likely due to System Integrity Protection being re-enabled after installation of the helper tool. \ 132 | Ignoring since this is a success from an uninstallation perspective. 133 | """) 134 | } catch CodeInjector.InjectError.failedToUnapplyPatch(patchError: .failedToFindTargetData) { 135 | os_log(.error, 136 | "Failed to find the patched data nor the original data. Ignoring since this is a success from an uninstallation perspective.") 137 | } catch { 138 | throw UninstallPrivilegedHelperError.failedToRemoveCodeInjection 139 | } 140 | 141 | os_log("Removed code injection.") 142 | } 143 | 144 | private static let timeoutInSecondsWaitingForLaunchdToKillUs: UInt32 = 5 145 | 146 | private static func unregisterPrivilegedHelperInLaunchd() throws -> Never { 147 | let launchctlExecutablePath = "/bin/launchctl" 148 | 149 | let launchctlProcess = Process() 150 | launchctlProcess.executableURL = URL(fileURLWithPath: launchctlExecutablePath) 151 | launchctlProcess.arguments = [ 152 | "remove", 153 | PrivilegedHelperInfo.shared.launchdLabel 154 | ] 155 | 156 | os_log("Unregistering the privileged helper in launchd.") 157 | 158 | do { 159 | try launchctlProcess.run() 160 | } catch { 161 | os_log(.fault, 162 | "Failed to run `%{public}@`: %{public}@.", 163 | launchctlExecutablePath, 164 | String(describing: error)) 165 | throw UninstallPrivilegedHelperError.failedToRunLaunchctlProcess 166 | } 167 | launchctlProcess.waitUntilExit() 168 | 169 | guard launchctlProcess.terminationReason == .exit else { 170 | os_log(.fault, 171 | "`%{public}@` was killed by an uncaught signal.", 172 | launchctlExecutablePath) 173 | throw UninstallPrivilegedHelperError.launchctlFailed 174 | } 175 | 176 | let launchctlStatus = launchctlProcess.terminationStatus 177 | guard launchctlStatus == 0 else { 178 | os_log(.fault, 179 | "`%{public}@` failed: %d.", 180 | launchctlExecutablePath, 181 | launchctlStatus) 182 | throw UninstallPrivilegedHelperError.launchctlFailed 183 | } 184 | 185 | sleep(timeoutInSecondsWaitingForLaunchdToKillUs) 186 | 187 | throw UninstallPrivilegedHelperError.timedOutWaitingForLaunchdToKillPrivilegedHelper 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /AirPlayEnabler/Code Injection/Patch.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Patch.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-21. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | import Darwin 10 | 11 | struct Patch { 12 | // MARK: - Initialization 13 | 14 | init(addressInExecutableFile: mach_vm_address_t, 15 | requirements: [Requirement], 16 | target: MemoryData, 17 | replacement: InjectedCode, 18 | originalMemoryProtection: vm_prot_t) { 19 | precondition(target.count == replacement.count) 20 | 21 | self.addressInExecutableFile = addressInExecutableFile 22 | self.requirements = requirements 23 | self.target = target 24 | self.replacement = replacement 25 | self.originalMemoryProtection = originalMemoryProtection 26 | } 27 | 28 | // MARK: - Properties 29 | 30 | private let addressInExecutableFile: mach_vm_address_t 31 | private let requirements: [Requirement] 32 | private let target: MemoryData 33 | private let replacement: InjectedCode 34 | private let originalMemoryProtection: vm_prot_t 35 | 36 | // MARK: - Applying/Unapplying the Patch 37 | 38 | enum PatchError: Error { 39 | case failedToReadTargetProcessMemory 40 | case unsupportedTargetByteOrder 41 | case failedToMakeInjectedCodeData(injectedCodeError: InjectedCode.DataCreationError) 42 | case requirementNotSatisfied 43 | case failedToFindTargetData 44 | case failedToModifyTargetDataMemoryProtection 45 | case failedToReplaceTargetData 46 | case failedToRestoreTargetData 47 | case failedToRestoreTargetDataMemoryProtection 48 | } 49 | 50 | func needsPatch(forExecutableDescribedBy executableInfo: ExecutableInfo) throws -> Bool { 51 | return try OSInitiateActivity(named: "\(type(of: self)).\(#function)") { 52 | let replacementData = try self.makeReplacementData(forExecutableDescribedBy: executableInfo) 53 | return try _needsPatch(forExecutableDescribedBy: executableInfo, 54 | replacementData: replacementData) 55 | } 56 | } 57 | 58 | private func _needsPatch(forExecutableDescribedBy executableInfo: ExecutableInfo, 59 | replacementData: InjectedCode.Data) throws -> Bool { 60 | let addressInTaskSpace = executableInfo.addressInTaskSpace(fromAddressInExecutableFile: addressInExecutableFile) 61 | guard let taskData = Data(contentsOf: addressInTaskSpace, byteCount: mach_vm_size_t(target.count), inTaskVMDescribedBy: executableInfo.taskVMMap) else { 62 | throw PatchError.failedToReadTargetProcessMemory 63 | } 64 | 65 | if taskData == replacementData { 66 | return false 67 | } 68 | 69 | let targetDataRequirement = Requirement(addressInExecutableFile: addressInExecutableFile, 70 | requiredMemoryData: target) 71 | guard try targetDataRequirement.isSatisfied(byExecutableDescribedBy: executableInfo) else { 72 | throw PatchError.failedToFindTargetData 73 | } 74 | 75 | return true 76 | } 77 | 78 | func apply(toExecutableDescribedBy executableInfo: ExecutableInfo) throws { 79 | try OSInitiateActivity(named: "\(type(of: self)).\(#function)") { 80 | try _apply(toExecutableDescribedBy: executableInfo) 81 | } 82 | } 83 | 84 | func _apply(toExecutableDescribedBy executableInfo: ExecutableInfo) throws { 85 | let addressInTaskSpace = executableInfo.addressInTaskSpace(fromAddressInExecutableFile: addressInExecutableFile) 86 | let replacementData = try self.makeReplacementData(forExecutableDescribedBy: executableInfo) 87 | 88 | guard try _needsPatch(forExecutableDescribedBy: executableInfo, replacementData: replacementData) else { 89 | os_log("Target data at 0x%llx (in task space) has already been patched; skipping.", 90 | addressInTaskSpace) 91 | return 92 | } 93 | 94 | for requirement in requirements { 95 | let isRequirementSatisfied = try requirement.isSatisfied(byExecutableDescribedBy: executableInfo) 96 | if !isRequirementSatisfied { 97 | os_log(.error, 98 | "Requirement not satisfied: %{public}@.", 99 | String(describing: requirement)) 100 | throw PatchError.requirementNotSatisfied 101 | } 102 | } 103 | 104 | os_log(.info, 105 | "Patching task memory at address 0x%llx.", 106 | addressInTaskSpace) 107 | 108 | let replacementDataByteCount = replacementData.count 109 | 110 | let status = mach_vm_protect(executableInfo.taskVMMap, 111 | addressInTaskSpace, 112 | mach_vm_size_t(replacementDataByteCount), 113 | 0, // set_maximum: boolean_t 114 | VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE) 115 | if status != KERN_SUCCESS { 116 | os_log(.error, 117 | "mach_vm_protect failed: %d.", 118 | status) 119 | throw PatchError.failedToModifyTargetDataMemoryProtection 120 | } 121 | 122 | try replacementData.withUnsafeBytes { (pointer: UnsafePointer) in 123 | let status = mach_vm_write(executableInfo.taskVMMap, 124 | addressInTaskSpace, 125 | vm_offset_t(bitPattern: pointer), 126 | mach_msg_type_number_t(replacementDataByteCount)) 127 | if status != KERN_SUCCESS { 128 | os_log(.error, 129 | "mach_vm_write failed: %d.", 130 | status) 131 | throw PatchError.failedToReplaceTargetData 132 | } 133 | } 134 | 135 | os_log("Successfully applied patch to 0x%llx (in task space).", 136 | addressInTaskSpace) 137 | } 138 | 139 | func unapply(toExecutableDescribedBy executableInfo: ExecutableInfo) throws { 140 | try OSInitiateActivity(named: "\(type(of: self)).\(#function)") { 141 | try _unapply(toExecutableDescribedBy: executableInfo) 142 | } 143 | } 144 | 145 | func _unapply(toExecutableDescribedBy executableInfo: ExecutableInfo) throws { 146 | let addressInTaskSpace = executableInfo.addressInTaskSpace(fromAddressInExecutableFile: addressInExecutableFile) 147 | let replacementData = try self.makeReplacementData(forExecutableDescribedBy: executableInfo) 148 | 149 | guard try !_needsPatch(forExecutableDescribedBy: executableInfo, replacementData: replacementData) else { 150 | os_log("Target data at 0x%llx (in task space) has not been patched; skipping.", 151 | addressInTaskSpace) 152 | return 153 | } 154 | 155 | os_log(.info, 156 | "Unapplying patch to task memory at address 0x%llx.", 157 | addressInTaskSpace) 158 | 159 | guard let targetData = target.data(in: executableInfo.executableFileByteOrder) else { 160 | throw PatchError.unsupportedTargetByteOrder 161 | } 162 | let targetDataByteCount = targetData.count 163 | 164 | try targetData.withUnsafeBytes { (pointer: UnsafePointer) in 165 | let status = mach_vm_write(executableInfo.taskVMMap, 166 | addressInTaskSpace, 167 | vm_offset_t(bitPattern: pointer), 168 | mach_msg_type_number_t(targetDataByteCount)) 169 | if status != KERN_SUCCESS { 170 | os_log(.error, 171 | "mach_vm_write failed: %d.", 172 | status) 173 | throw PatchError.failedToRestoreTargetData 174 | } 175 | } 176 | 177 | let status = mach_vm_protect(executableInfo.taskVMMap, 178 | addressInTaskSpace, 179 | mach_vm_size_t(targetDataByteCount), 180 | 0, // set_maximum: boolean_t 181 | originalMemoryProtection) 182 | if status != KERN_SUCCESS { 183 | os_log(.error, 184 | "mach_vm_protect failed: %d.", 185 | status) 186 | throw PatchError.failedToRestoreTargetDataMemoryProtection 187 | } 188 | 189 | os_log("Successfully unapplied patch to 0x%llx (in task space).", 190 | addressInTaskSpace) 191 | } 192 | 193 | private func makeReplacementData(forExecutableDescribedBy executableInfo: ExecutableInfo) throws -> InjectedCode.Data { 194 | do { 195 | return try replacement.makeData(forExecutableDescribedBy: executableInfo) 196 | } catch let error as InjectedCode.DataCreationError { 197 | throw PatchError.failedToMakeInjectedCodeData(injectedCodeError: error) 198 | } catch { 199 | fatalError("Caught error that is not of type `InjectedCode.DataCreationError`: \(error).") 200 | } 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /Injected Code/macOS 10.14/InjectedCode.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | E648E30521CC51A300FB35E4 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = E648E30421CC51A300FB35E4 /* main.c */; }; 11 | E648E30D21CC51B100FB35E4 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E648E30C21CC51B100FB35E4 /* Security.framework */; }; 12 | E648E30F21CC51C000FB35E4 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E648E30E21CC51BF00FB35E4 /* CoreFoundation.framework */; }; 13 | E648E31221CC526E00FB35E4 /* Injection.c in Sources */ = {isa = PBXBuildFile; fileRef = E648E31121CC526E00FB35E4 /* Injection.c */; }; 14 | /* End PBXBuildFile section */ 15 | 16 | /* Begin PBXCopyFilesBuildPhase section */ 17 | E648E2FF21CC51A300FB35E4 /* CopyFiles */ = { 18 | isa = PBXCopyFilesBuildPhase; 19 | buildActionMask = 2147483647; 20 | dstPath = /usr/share/man/man1/; 21 | dstSubfolderSpec = 0; 22 | files = ( 23 | ); 24 | runOnlyForDeploymentPostprocessing = 1; 25 | }; 26 | /* End PBXCopyFilesBuildPhase section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | E648E30121CC51A300FB35E4 /* InjectedCode */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = InjectedCode; sourceTree = BUILT_PRODUCTS_DIR; }; 30 | E648E30421CC51A300FB35E4 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; 31 | E648E30C21CC51B100FB35E4 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 32 | E648E30E21CC51BF00FB35E4 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 33 | E648E31021CC526E00FB35E4 /* Injection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Injection.h; sourceTree = ""; }; 34 | E648E31121CC526E00FB35E4 /* Injection.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = Injection.c; sourceTree = ""; }; 35 | /* End PBXFileReference section */ 36 | 37 | /* Begin PBXFrameworksBuildPhase section */ 38 | E648E2FE21CC51A300FB35E4 /* Frameworks */ = { 39 | isa = PBXFrameworksBuildPhase; 40 | buildActionMask = 2147483647; 41 | files = ( 42 | E648E30F21CC51C000FB35E4 /* CoreFoundation.framework in Frameworks */, 43 | E648E30D21CC51B100FB35E4 /* Security.framework in Frameworks */, 44 | ); 45 | runOnlyForDeploymentPostprocessing = 0; 46 | }; 47 | /* End PBXFrameworksBuildPhase section */ 48 | 49 | /* Begin PBXGroup section */ 50 | E648E2F821CC51A300FB35E4 = { 51 | isa = PBXGroup; 52 | children = ( 53 | E648E30321CC51A300FB35E4 /* InjectedCode */, 54 | E648E30221CC51A300FB35E4 /* Products */, 55 | E648E30B21CC51B100FB35E4 /* Frameworks */, 56 | ); 57 | sourceTree = ""; 58 | }; 59 | E648E30221CC51A300FB35E4 /* Products */ = { 60 | isa = PBXGroup; 61 | children = ( 62 | E648E30121CC51A300FB35E4 /* InjectedCode */, 63 | ); 64 | name = Products; 65 | sourceTree = ""; 66 | }; 67 | E648E30321CC51A300FB35E4 /* InjectedCode */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | E648E30421CC51A300FB35E4 /* main.c */, 71 | E648E31021CC526E00FB35E4 /* Injection.h */, 72 | E648E31121CC526E00FB35E4 /* Injection.c */, 73 | ); 74 | path = InjectedCode; 75 | sourceTree = ""; 76 | }; 77 | E648E30B21CC51B100FB35E4 /* Frameworks */ = { 78 | isa = PBXGroup; 79 | children = ( 80 | E648E30E21CC51BF00FB35E4 /* CoreFoundation.framework */, 81 | E648E30C21CC51B100FB35E4 /* Security.framework */, 82 | ); 83 | name = Frameworks; 84 | sourceTree = ""; 85 | }; 86 | /* End PBXGroup section */ 87 | 88 | /* Begin PBXNativeTarget section */ 89 | E648E30021CC51A300FB35E4 /* InjectedCode */ = { 90 | isa = PBXNativeTarget; 91 | buildConfigurationList = E648E30821CC51A300FB35E4 /* Build configuration list for PBXNativeTarget "InjectedCode" */; 92 | buildPhases = ( 93 | E648E2FD21CC51A300FB35E4 /* Sources */, 94 | E648E2FE21CC51A300FB35E4 /* Frameworks */, 95 | E648E2FF21CC51A300FB35E4 /* CopyFiles */, 96 | ); 97 | buildRules = ( 98 | ); 99 | dependencies = ( 100 | ); 101 | name = InjectedCode; 102 | productName = InjectedCode; 103 | productReference = E648E30121CC51A300FB35E4 /* InjectedCode */; 104 | productType = "com.apple.product-type.tool"; 105 | }; 106 | /* End PBXNativeTarget section */ 107 | 108 | /* Begin PBXProject section */ 109 | E648E2F921CC51A300FB35E4 /* Project object */ = { 110 | isa = PBXProject; 111 | attributes = { 112 | LastUpgradeCheck = 1010; 113 | ORGANIZATIONNAME = "Darren Mo"; 114 | TargetAttributes = { 115 | E648E30021CC51A300FB35E4 = { 116 | CreatedOnToolsVersion = 10.1; 117 | }; 118 | }; 119 | }; 120 | buildConfigurationList = E648E2FC21CC51A300FB35E4 /* Build configuration list for PBXProject "InjectedCode" */; 121 | compatibilityVersion = "Xcode 9.3"; 122 | developmentRegion = en; 123 | hasScannedForEncodings = 0; 124 | knownRegions = ( 125 | en, 126 | ); 127 | mainGroup = E648E2F821CC51A300FB35E4; 128 | productRefGroup = E648E30221CC51A300FB35E4 /* Products */; 129 | projectDirPath = ""; 130 | projectRoot = ""; 131 | targets = ( 132 | E648E30021CC51A300FB35E4 /* InjectedCode */, 133 | ); 134 | }; 135 | /* End PBXProject section */ 136 | 137 | /* Begin PBXSourcesBuildPhase section */ 138 | E648E2FD21CC51A300FB35E4 /* Sources */ = { 139 | isa = PBXSourcesBuildPhase; 140 | buildActionMask = 2147483647; 141 | files = ( 142 | E648E30521CC51A300FB35E4 /* main.c in Sources */, 143 | E648E31221CC526E00FB35E4 /* Injection.c in Sources */, 144 | ); 145 | runOnlyForDeploymentPostprocessing = 0; 146 | }; 147 | /* End PBXSourcesBuildPhase section */ 148 | 149 | /* Begin XCBuildConfiguration section */ 150 | E648E30621CC51A300FB35E4 /* Debug */ = { 151 | isa = XCBuildConfiguration; 152 | buildSettings = { 153 | ALWAYS_SEARCH_USER_PATHS = NO; 154 | CLANG_ANALYZER_NONNULL = YES; 155 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 156 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 157 | CLANG_CXX_LIBRARY = "libc++"; 158 | CLANG_ENABLE_MODULES = YES; 159 | CLANG_ENABLE_OBJC_ARC = YES; 160 | CLANG_ENABLE_OBJC_WEAK = YES; 161 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 162 | CLANG_WARN_BOOL_CONVERSION = YES; 163 | CLANG_WARN_COMMA = YES; 164 | CLANG_WARN_CONSTANT_CONVERSION = YES; 165 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 166 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 167 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 168 | CLANG_WARN_EMPTY_BODY = YES; 169 | CLANG_WARN_ENUM_CONVERSION = YES; 170 | CLANG_WARN_INFINITE_RECURSION = YES; 171 | CLANG_WARN_INT_CONVERSION = YES; 172 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 173 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 174 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 175 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 176 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 177 | CLANG_WARN_STRICT_PROTOTYPES = YES; 178 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 179 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 180 | CLANG_WARN_UNREACHABLE_CODE = YES; 181 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 182 | CODE_SIGN_IDENTITY = "Mac Developer"; 183 | COPY_PHASE_STRIP = NO; 184 | DEBUG_INFORMATION_FORMAT = dwarf; 185 | ENABLE_STRICT_OBJC_MSGSEND = YES; 186 | ENABLE_TESTABILITY = YES; 187 | GCC_C_LANGUAGE_STANDARD = gnu11; 188 | GCC_DYNAMIC_NO_PIC = NO; 189 | GCC_NO_COMMON_BLOCKS = YES; 190 | GCC_OPTIMIZATION_LEVEL = 0; 191 | GCC_PREPROCESSOR_DEFINITIONS = ( 192 | "DEBUG=1", 193 | "$(inherited)", 194 | ); 195 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 196 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 197 | GCC_WARN_UNDECLARED_SELECTOR = YES; 198 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 199 | GCC_WARN_UNUSED_FUNCTION = YES; 200 | GCC_WARN_UNUSED_VARIABLE = YES; 201 | MACOSX_DEPLOYMENT_TARGET = 10.14; 202 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 203 | MTL_FAST_MATH = YES; 204 | ONLY_ACTIVE_ARCH = YES; 205 | SDKROOT = macosx; 206 | }; 207 | name = Debug; 208 | }; 209 | E648E30721CC51A300FB35E4 /* Release */ = { 210 | isa = XCBuildConfiguration; 211 | buildSettings = { 212 | ALWAYS_SEARCH_USER_PATHS = NO; 213 | CLANG_ANALYZER_NONNULL = YES; 214 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 215 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 216 | CLANG_CXX_LIBRARY = "libc++"; 217 | CLANG_ENABLE_MODULES = YES; 218 | CLANG_ENABLE_OBJC_ARC = YES; 219 | CLANG_ENABLE_OBJC_WEAK = YES; 220 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 221 | CLANG_WARN_BOOL_CONVERSION = YES; 222 | CLANG_WARN_COMMA = YES; 223 | CLANG_WARN_CONSTANT_CONVERSION = YES; 224 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 225 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 226 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 227 | CLANG_WARN_EMPTY_BODY = YES; 228 | CLANG_WARN_ENUM_CONVERSION = YES; 229 | CLANG_WARN_INFINITE_RECURSION = YES; 230 | CLANG_WARN_INT_CONVERSION = YES; 231 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 232 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 233 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 234 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 235 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 236 | CLANG_WARN_STRICT_PROTOTYPES = YES; 237 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 238 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 239 | CLANG_WARN_UNREACHABLE_CODE = YES; 240 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 241 | CODE_SIGN_IDENTITY = "Mac Developer"; 242 | COPY_PHASE_STRIP = NO; 243 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 244 | ENABLE_NS_ASSERTIONS = NO; 245 | ENABLE_STRICT_OBJC_MSGSEND = YES; 246 | GCC_C_LANGUAGE_STANDARD = gnu11; 247 | GCC_NO_COMMON_BLOCKS = YES; 248 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 249 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 250 | GCC_WARN_UNDECLARED_SELECTOR = YES; 251 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 252 | GCC_WARN_UNUSED_FUNCTION = YES; 253 | GCC_WARN_UNUSED_VARIABLE = YES; 254 | MACOSX_DEPLOYMENT_TARGET = 10.14; 255 | MTL_ENABLE_DEBUG_INFO = NO; 256 | MTL_FAST_MATH = YES; 257 | SDKROOT = macosx; 258 | }; 259 | name = Release; 260 | }; 261 | E648E30921CC51A300FB35E4 /* Debug */ = { 262 | isa = XCBuildConfiguration; 263 | buildSettings = { 264 | CODE_SIGN_STYLE = Automatic; 265 | DEVELOPMENT_TEAM = PVLQ49LAH3; 266 | LIBRARY_SEARCH_PATHS = ( 267 | "$(inherited)", 268 | "$(SDKROOT)/usr/lib/system/introspection", 269 | ); 270 | PRODUCT_NAME = "$(TARGET_NAME)"; 271 | }; 272 | name = Debug; 273 | }; 274 | E648E30A21CC51A300FB35E4 /* Release */ = { 275 | isa = XCBuildConfiguration; 276 | buildSettings = { 277 | CODE_SIGN_STYLE = Automatic; 278 | DEVELOPMENT_TEAM = PVLQ49LAH3; 279 | LIBRARY_SEARCH_PATHS = ( 280 | "$(inherited)", 281 | "$(SDKROOT)/usr/lib/system/introspection", 282 | ); 283 | PRODUCT_NAME = "$(TARGET_NAME)"; 284 | }; 285 | name = Release; 286 | }; 287 | /* End XCBuildConfiguration section */ 288 | 289 | /* Begin XCConfigurationList section */ 290 | E648E2FC21CC51A300FB35E4 /* Build configuration list for PBXProject "InjectedCode" */ = { 291 | isa = XCConfigurationList; 292 | buildConfigurations = ( 293 | E648E30621CC51A300FB35E4 /* Debug */, 294 | E648E30721CC51A300FB35E4 /* Release */, 295 | ); 296 | defaultConfigurationIsVisible = 0; 297 | defaultConfigurationName = Release; 298 | }; 299 | E648E30821CC51A300FB35E4 /* Build configuration list for PBXNativeTarget "InjectedCode" */ = { 300 | isa = XCConfigurationList; 301 | buildConfigurations = ( 302 | E648E30921CC51A300FB35E4 /* Debug */, 303 | E648E30A21CC51A300FB35E4 /* Release */, 304 | ); 305 | defaultConfigurationIsVisible = 0; 306 | defaultConfigurationName = Release; 307 | }; 308 | /* End XCConfigurationList section */ 309 | }; 310 | rootObject = E648E2F921CC51A300FB35E4 /* Project object */; 311 | } 312 | -------------------------------------------------------------------------------- /AirPlayEnabler/Code Injection/CodeInjector.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CodeInjector.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-12. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | import Darwin 10 | import Foundation 11 | import MachO 12 | 13 | class CodeInjector { 14 | // MARK: - Initialization 15 | 16 | static let shared = CodeInjector() 17 | 18 | private init() { 19 | } 20 | 21 | private let serialQueue = DispatchQueue(label: "Code Injector Queue") 22 | 23 | // MARK: - Errors 24 | 25 | enum InjectError: Error { 26 | case pgrepProcessRunError(underlyingError: Error) 27 | case pgrepFailed 28 | case invalidPgrepOutput(output: Data) 29 | case failedToFindTargetProcess 30 | case tooManyTargetProcesses 31 | case failedToAttachToTargetProcess 32 | case failedToSuspendTargetProcess 33 | case failedToReadExecutableInfo 34 | case failedToApplyPatch(patchError: Patch.PatchError) 35 | case failedToUnapplyPatch(patchError: Patch.PatchError) 36 | } 37 | private(set) var latestError: InjectError? 38 | 39 | // MARK: - Initializing the Executable Info 40 | 41 | private var _executableInfo: ExecutableInfo? 42 | private func executableInfo() throws -> ExecutableInfo { 43 | if let executableInfo = _executableInfo { 44 | os_log(.info, "Executable info has been previously found; reusing.") 45 | return executableInfo 46 | } 47 | 48 | os_log("Executable info not found; will try to populate it.") 49 | 50 | let amfidPIDs = try CodeInjector.findPIDs(forProcessesNamed: "amfid") 51 | guard !amfidPIDs.isEmpty else { 52 | throw InjectError.failedToFindTargetProcess 53 | } 54 | guard amfidPIDs.count == 1 else { 55 | os_log(.error, "Unexpectedly found multiple amfid PIDs.") 56 | throw InjectError.tooManyTargetProcesses 57 | } 58 | 59 | let amfidPID = amfidPIDs.first! 60 | os_log("Found amfid PID: %d.", amfidPID); 61 | 62 | let executableInfo: ExecutableInfo 63 | do { 64 | executableInfo = try CodeInjector.readExecutableInfo(inProcessIdentifiedBy: amfidPID) 65 | } catch let error as InjectError { 66 | latestError = error 67 | throw error 68 | } 69 | 70 | _executableInfo = executableInfo 71 | os_log("Successfully populated executable info.") 72 | 73 | return executableInfo 74 | } 75 | 76 | // MARK: - Checking Activation Status 77 | 78 | func isCodeInjectionActive() -> Bool { 79 | var isCodeInjectionActive = false 80 | serialQueue.sync { 81 | isCodeInjectionActive = _isCodeInjectionActive() 82 | } 83 | return isCodeInjectionActive 84 | } 85 | 86 | private func _isCodeInjectionActive() -> Bool { 87 | do { 88 | let executableInfo = try self.executableInfo() 89 | 90 | let patches = Patch.makePatchesForCurrentOperatingSystem() 91 | for patch in patches { 92 | let needsPatch = try patch.needsPatch(forExecutableDescribedBy: executableInfo) 93 | if needsPatch { 94 | return false 95 | } 96 | } 97 | 98 | return true 99 | } catch Patch.PatchError.failedToFindTargetData { 100 | return false 101 | } catch { 102 | os_log(.error, 103 | "Failed to check code injection activation status: %{public}@; assuming code injection is inactive.", 104 | String(describing: error)) 105 | return false 106 | } 107 | } 108 | 109 | // MARK: - Injecting Code 110 | 111 | func injectCode() throws { 112 | try OSInitiateActivity(named: "\(type(of: self)).\(#function)") { 113 | try serialQueue.sync { 114 | try _injectCode() 115 | } 116 | } 117 | } 118 | 119 | private func _injectCode() throws { 120 | os_log("Starting code injection.") 121 | 122 | do { 123 | do { 124 | let executableInfo = try self.executableInfo() 125 | 126 | let patches = Patch.makePatchesForCurrentOperatingSystem() 127 | try CodeInjector.whileSuspendingTask(executableInfo.taskVMMap) { 128 | for (idx, patch) in patches.enumerated() { 129 | do { 130 | do { 131 | try patch.apply(toExecutableDescribedBy: executableInfo) 132 | } catch let error as Patch.PatchError { 133 | throw InjectError.failedToApplyPatch(patchError: error) 134 | } 135 | } catch { 136 | os_log("Failed to apply patch. Unapplying already-applied patches.") 137 | 138 | for patch in patches[0.. [pid_t] { 218 | os_log(.info, 219 | "Trying to find processes named `%{public}@`.", 220 | processName) 221 | 222 | let pgrepProcess = Process() 223 | let pgrepExecutablePath = "/usr/bin/pgrep" 224 | pgrepProcess.executableURL = URL(fileURLWithPath: pgrepExecutablePath) 225 | pgrepProcess.arguments = ["^\(processName)$"] 226 | 227 | let standardOutputPipe = Pipe() 228 | pgrepProcess.standardOutput = standardOutputPipe 229 | 230 | do { 231 | try pgrepProcess.run() 232 | } catch { 233 | os_log(.fault, 234 | "Failed to run `%{public}@`: %{public}@.", 235 | pgrepExecutablePath, 236 | String(describing: error)) 237 | throw error 238 | } 239 | 240 | let standardOutputData = standardOutputPipe.fileHandleForReading.readDataToEndOfFile() 241 | pgrepProcess.waitUntilExit() 242 | 243 | guard pgrepProcess.terminationReason == .exit else { 244 | os_log(.fault, 245 | "`%{public}@` was killed by an uncaught signal.", 246 | pgrepExecutablePath) 247 | throw InjectError.pgrepFailed 248 | } 249 | 250 | let pgrepStatus = pgrepProcess.terminationStatus 251 | guard pgrepStatus == 0 else { 252 | os_log(.fault, 253 | "`%{public}@` failed: %d.", 254 | pgrepExecutablePath, 255 | pgrepStatus) 256 | throw InjectError.pgrepFailed 257 | } 258 | 259 | guard let standardOutputString = String(data: standardOutputData, encoding: .utf8) else { 260 | os_log(.error, 261 | "`%{public}@` sent non-UTF-8-encoded data to its standard output: %{public}@.", 262 | pgrepExecutablePath, 263 | (standardOutputData as NSData).description) 264 | throw InjectError.invalidPgrepOutput(output: standardOutputData) 265 | } 266 | 267 | let pidStrings = standardOutputString.split(separator: "\n") 268 | let pids = try pidStrings.map { (pidString) -> pid_t in 269 | guard let pid = pid_t(pidString) else { 270 | os_log(.fault, 271 | "`%{public}@` sent an incorrectly-formatted PID string to its standard output: %{public}@.", 272 | pgrepExecutablePath, 273 | String(pidString)) 274 | throw InjectError.invalidPgrepOutput(output: standardOutputData) 275 | } 276 | return pid 277 | } 278 | 279 | return pids 280 | } 281 | 282 | private static func readExecutableInfo(inProcessIdentifiedBy targetPID: pid_t) throws -> ExecutableInfo { 283 | var targetTask: mach_port_name_t = 0 284 | var status = task_for_pid(mach_task_self_, targetPID, &targetTask) 285 | if status != KERN_SUCCESS { 286 | os_log(.error, 287 | "task_for_pid failed: %d.", 288 | status) 289 | throw InjectError.failedToAttachToTargetProcess 290 | } 291 | 292 | var executableInfo = ExecutableInfo() 293 | status = try whileSuspendingTask(targetTask) { 294 | return ExecutableInfo.populate(fromTaskVMDescribedBy: targetTask, 295 | forExecutableFilePath: "/usr/libexec/amfid", 296 | executableInfoOut: &executableInfo) 297 | } 298 | if status != KERN_SUCCESS { 299 | os_log(.error, 300 | "ExecutableInfo.populate failed: %d.", 301 | status) 302 | throw InjectError.failedToReadExecutableInfo 303 | } 304 | 305 | return executableInfo 306 | } 307 | 308 | private static func whileSuspendingTask(_ targetTask: mach_port_name_t, 309 | do execute: () throws -> ReturnType) throws -> ReturnType { 310 | var taskSuspensionToken: task_suspension_token_t = 0 311 | let status = task_suspend2(targetTask, &taskSuspensionToken) 312 | if status != KERN_SUCCESS { 313 | os_log(.error, 314 | "task_suspend2 failed: %d.", 315 | status) 316 | throw InjectError.failedToSuspendTargetProcess 317 | } 318 | os_log("Successfully suspended target task.") 319 | 320 | defer { 321 | let status = task_resume2(taskSuspensionToken) 322 | if status != KERN_SUCCESS { 323 | os_log(.fault, 324 | "task_resume2 failed: %d. This is quite serious because processes cannot be launched without first going through amfid. Unfortunately, there is nothing we can do about it.", 325 | status) 326 | } else { 327 | os_log("Successfully resumed target task.") 328 | } 329 | } 330 | 331 | return try execute() 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /AirPlayEnabler/Code Injection/Low-Level Functions/ExecutableInfo.m: -------------------------------------------------------------------------------- 1 | // 2 | // ExecutableInfo.m 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-12. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | // Inspired by fG!: https://sourceforge.net/p/machoview/code/ci/master/tree/Attach.mm 9 | // 10 | 11 | #import "ExecutableInfo.h" 12 | 13 | @import os.activity; 14 | @import os.log; 15 | 16 | #import "Common.h" 17 | #import "ImageInfo.h" 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | // MARK: - Static Function Declarations 22 | 23 | static kern_return_t _ape_executable_info_populate(vm_map_t task_vm_map, 24 | const char *executable_file_path, 25 | struct ape_executable_info *executable_info_out); 26 | static kern_return_t read_executable_header_at_address(vm_map_t task_vm_map, 27 | mach_vm_address_t address_in_task_space, 28 | bool *is_supported_executable_out, 29 | struct ape_executable_info *executable_info_out); 30 | static kern_return_t determine_aslr_offset(vm_map_t task_vm_map, 31 | struct ape_executable_info *executable_info_inout); 32 | 33 | // MARK: - Function Definitions 34 | 35 | kern_return_t ape_executable_info_populate(vm_map_t task_vm_map, 36 | const char *executable_file_path, 37 | struct ape_executable_info *executable_info_out) { 38 | __block kern_return_t status = KERN_SUCCESS; 39 | 40 | const char *function_name = __FUNCTION__; 41 | os_activity_initiate("ape_executable_info_populate", OS_ACTIVITY_FLAG_DEFAULT, ^{ 42 | os_log_debug(OS_LOG_DEFAULT, 43 | "Entering %s.", 44 | function_name); 45 | 46 | status = _ape_executable_info_populate(task_vm_map, 47 | executable_file_path, 48 | executable_info_out); 49 | 50 | os_log_debug(OS_LOG_DEFAULT, 51 | "Exiting %s with return value %d.", 52 | function_name, 53 | status); 54 | }); 55 | 56 | return status; 57 | } 58 | 59 | static kern_return_t _ape_executable_info_populate(vm_map_t task_vm_map, 60 | const char *executable_file_path, 61 | struct ape_executable_info *executable_info_out) { 62 | if (executable_file_path == NULL) { 63 | os_log_error(OS_LOG_DEFAULT, "executable_file_path should not be NULL."); 64 | return KERN_INVALID_ARGUMENT; 65 | } 66 | if (executable_info_out == NULL) { 67 | os_log_error(OS_LOG_DEFAULT, "executable_info_out should not be NULL."); 68 | return KERN_INVALID_ARGUMENT; 69 | } 70 | 71 | struct task_dyld_info dyld_info = {0}; 72 | mach_msg_type_number_t task_info_count = TASK_DYLD_INFO_COUNT; 73 | kern_return_t status = task_info(task_vm_map, 74 | TASK_DYLD_INFO, 75 | (task_info_t)&dyld_info, 76 | &task_info_count); 77 | if (status != KERN_SUCCESS) { 78 | os_log_error(OS_LOG_DEFAULT, 79 | "task_info failed: %d.", 80 | status); 81 | return KERN_FAILURE; 82 | } else if (task_info_count != TASK_DYLD_INFO_COUNT) { 83 | os_log_fault(OS_LOG_DEFAULT, 84 | "task_info returned info count that does not correspond to task_dyld_info struct: %u.", 85 | task_info_count); 86 | return KERN_FAILURE; 87 | } 88 | 89 | integer_t dyld_all_image_infos_format = dyld_info.all_image_info_format; 90 | if (dyld_all_image_infos_format != TASK_DYLD_ALL_IMAGE_INFO_64) { 91 | os_log_error(OS_LOG_DEFAULT, 92 | "Unsupported dyld_all_image_infos format: %d.", 93 | dyld_all_image_infos_format); 94 | return KERN_FAILURE; 95 | } 96 | 97 | mach_vm_address_t dyld_all_image_infos_address_in_task_space = dyld_info.all_image_info_addr; 98 | 99 | struct ape_image_info image_info = {0}; 100 | status = ape_image_info_find(task_vm_map, 101 | dyld_all_image_infos_address_in_task_space, 102 | executable_file_path, 103 | &image_info); 104 | if (status != KERN_SUCCESS) { 105 | os_log_error(OS_LOG_DEFAULT, 106 | "ape_image_info_find failed: %d.", 107 | status); 108 | return KERN_FAILURE; 109 | } 110 | 111 | bool is_supported_executable = false; 112 | status = read_executable_header_at_address(task_vm_map, 113 | image_info.header_address_in_task_space, 114 | &is_supported_executable, 115 | executable_info_out); 116 | if (status != KERN_SUCCESS) { 117 | os_log_error(OS_LOG_DEFAULT, 118 | "read_executable_header_at_address failed: %d.", 119 | status); 120 | return KERN_FAILURE; 121 | } else if (!is_supported_executable) { 122 | os_log_error(OS_LOG_DEFAULT, 123 | "Unsupported executable format/architecture."); 124 | return KERN_FAILURE; 125 | } 126 | 127 | executable_info_out->dyld_all_image_infos_address_in_task_space = dyld_all_image_infos_address_in_task_space; 128 | 129 | return KERN_SUCCESS; 130 | } 131 | 132 | static kern_return_t read_executable_header_at_address(vm_map_t task_vm_map, 133 | mach_vm_address_t address_in_task_space, 134 | bool *is_supported_executable_out, 135 | struct ape_executable_info *executable_info_out) { 136 | ENTER_FUNCTION(); 137 | 138 | typeof(executable_info_out->header) header = {0}; 139 | mach_vm_size_t requested_header_size = sizeof(typeof(header)); 140 | mach_vm_size_t header_size = 0; 141 | 142 | kern_return_t status = mach_vm_read_overwrite(task_vm_map, 143 | address_in_task_space, 144 | requested_header_size, 145 | (mach_vm_address_t)&header, 146 | &header_size); 147 | if (status != KERN_SUCCESS) { 148 | os_log_error(OS_LOG_DEFAULT, 149 | "mach_vm_read_overwrite failed: %d.", 150 | status); 151 | EXIT_FUNCTION(KERN_FAILURE); 152 | } else if (header_size != requested_header_size) { 153 | os_log_error(OS_LOG_DEFAULT, 154 | "mach_vm_read_overwrite returned size (%{iec-bytes}llu) that is different from the requested size (%{iec-bytes}llu).", 155 | header_size, 156 | requested_header_size); 157 | EXIT_FUNCTION(KERN_FAILURE); 158 | } 159 | 160 | bool needs_byte_swap = false; 161 | if (header.magic == MH_CIGAM_64) { 162 | needs_byte_swap = true; 163 | 164 | os_log_info(OS_LOG_DEFAULT, 165 | "Found MH_CIGAM_64; swapping bytes in Mach-O header struct."); 166 | swap_mach_header_64(&header, NXHostByteOrder()); 167 | } 168 | 169 | *is_supported_executable_out = false; 170 | if (header.magic == MH_MAGIC_64) { 171 | if (header.cputype == CPU_TYPE_X86_64) { 172 | if (header.filetype == MH_EXECUTE) { 173 | os_log(OS_LOG_DEFAULT, 174 | "Found x86-64 executable Mach-O file whose header starts at 0x%llx (in task space).", 175 | address_in_task_space); 176 | 177 | struct ape_executable_info executable_info = { 178 | .task_vm_map = task_vm_map, 179 | .header_address_in_task_space = address_in_task_space, 180 | .header = header, 181 | .needs_byte_swap = needs_byte_swap 182 | }; 183 | 184 | status = determine_aslr_offset(task_vm_map, &executable_info); 185 | if (status != KERN_SUCCESS) { 186 | os_log_error(OS_LOG_DEFAULT, 187 | "determine_aslr_offset failed: %d.", 188 | status); 189 | EXIT_FUNCTION(KERN_FAILURE); 190 | } 191 | 192 | *is_supported_executable_out = true; 193 | *executable_info_out = executable_info; 194 | } else { 195 | os_log_info(OS_LOG_DEFAULT, "Region does not contain executable Mach-O file; skipping."); 196 | } 197 | } else { 198 | os_log_info(OS_LOG_DEFAULT, "Mach-O file is not for x86-64 platform; skipping."); 199 | } 200 | } else { 201 | os_log_info(OS_LOG_DEFAULT, 202 | "Mach-O header magic does not match MH_MAGIC_64: 0x%x; skipping.", 203 | header.magic); 204 | } 205 | 206 | EXIT_FUNCTION(KERN_SUCCESS); 207 | } 208 | 209 | static kern_return_t determine_aslr_offset(vm_map_t task_vm_map, 210 | struct ape_executable_info *executable_info_inout) { 211 | ENTER_FUNCTION(); 212 | 213 | mach_vm_address_t address_of_load_commands_in_task_space = executable_info_inout->header_address_in_task_space + sizeof(typeof(executable_info_inout->header)); 214 | uint32_t requested_load_commands_byte_count = executable_info_inout->header.sizeofcmds; 215 | 216 | vm_offset_t load_commands_pointer = 0; 217 | mach_msg_type_number_t load_commands_byte_count = 0; 218 | kern_return_t status = mach_vm_read(task_vm_map, 219 | address_of_load_commands_in_task_space, 220 | requested_load_commands_byte_count, 221 | &load_commands_pointer, 222 | &load_commands_byte_count); 223 | if (status != KERN_SUCCESS) { 224 | os_log_error(OS_LOG_DEFAULT, 225 | "mach_vm_read failed: %d.", 226 | status); 227 | EXIT_FUNCTION(KERN_FAILURE); 228 | } else if (load_commands_byte_count != requested_load_commands_byte_count) { 229 | os_log_error(OS_LOG_DEFAULT, 230 | "mach_vm_read returned data size (%{iec-bytes}u) that is different from the requested data size (%{iec-bytes}u).", 231 | load_commands_byte_count, 232 | requested_load_commands_byte_count); 233 | EXIT_FUNCTION(KERN_FAILURE); 234 | } 235 | 236 | bool needs_byte_swap = executable_info_inout->needs_byte_swap; 237 | 238 | bool foundNonZeroSegment = false; 239 | vm_offset_t current_load_commands_offset = 0; 240 | while (current_load_commands_offset < load_commands_byte_count) { 241 | os_log_info(OS_LOG_DEFAULT, 242 | "Now examining load command at load commands offset 0x%lx.", 243 | current_load_commands_offset); 244 | 245 | struct load_command *load_command = (struct load_command *)(load_commands_pointer + current_load_commands_offset); 246 | 247 | struct load_command load_command_local = *load_command; 248 | if (needs_byte_swap) { 249 | os_log_info(OS_LOG_DEFAULT, 250 | "Swapping bytes in load command struct."); 251 | swap_load_command(&load_command_local, NXHostByteOrder()); 252 | } 253 | 254 | uint32_t command_type = load_command_local.cmd; 255 | if (command_type == LC_SEGMENT_64) { 256 | struct segment_command_64 *segment_command = (struct segment_command_64 *)load_command; 257 | if (needs_byte_swap) { 258 | os_log_info(OS_LOG_DEFAULT, 259 | "Swapping bytes in segment command struct."); 260 | swap_segment_command_64(segment_command, NXHostByteOrder()); 261 | } 262 | 263 | if (segment_command->filesize > 0) { 264 | os_log(OS_LOG_DEFAULT, 265 | "Found first segment command that maps file data at load commands offset 0x%lx. This segment is supposed to be where the Mach-O header is located.", 266 | current_load_commands_offset); 267 | 268 | mach_vm_offset_t aslr_offset = executable_info_inout->header_address_in_task_space - segment_command->vmaddr; 269 | os_log(OS_LOG_DEFAULT, 270 | "Determined that the ASLR offset for the executable Mach-O file is 0x%llx.", 271 | aslr_offset); 272 | 273 | executable_info_inout->aslr_offset = aslr_offset; 274 | foundNonZeroSegment = true; 275 | break; 276 | } else { 277 | os_log_info(OS_LOG_DEFAULT, 278 | "Segment command does not map file data; skipping."); 279 | } 280 | } else { 281 | os_log_info(OS_LOG_DEFAULT, 282 | "Load command type is not LC_SEGMENT_64: %u; skipping.", 283 | command_type); 284 | } 285 | 286 | current_load_commands_offset += load_command_local.cmdsize; 287 | } 288 | 289 | status = mach_vm_deallocate(mach_task_self(), 290 | load_commands_pointer, 291 | load_commands_byte_count); 292 | if (status != KERN_SUCCESS) { 293 | os_log_fault(OS_LOG_DEFAULT, 294 | "mach_vm_deallocate failed: %d. Ignoring since it is a relatively small amount of data.", 295 | status); 296 | } 297 | 298 | if (!foundNonZeroSegment) { 299 | os_log_error(OS_LOG_DEFAULT, 300 | "Failed to find a segment command that maps file data."); 301 | EXIT_FUNCTION(KERN_FAILURE); 302 | } 303 | 304 | EXIT_FUNCTION(KERN_SUCCESS); 305 | } 306 | 307 | NS_ASSUME_NONNULL_END 308 | -------------------------------------------------------------------------------- /AirPlayEnabler/Code Injection/Patches/Patch+MacOS10_14.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Patch+MacOS10_14.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2018-12-21. 6 | // Copyright © 2018 Darren Mo. All rights reserved. 7 | // 8 | 9 | extension Patch { 10 | static func makePatchesForMacOS10_14() -> [Patch] { 11 | return [ 12 | makeInjectedCodePatch(), 13 | makeFunctionCallPatch() 14 | ] 15 | } 16 | 17 | private static func makeInjectedCodePatch() -> Patch { 18 | // c.f. "Injected Code/macOS 10.14/". 19 | return Patch(addressInExecutableFile: 0x100007ae0, 20 | requirements: [Requirement(addressInExecutableFile: 0x1000027ad, // _NSConcreteGlobalBlock check 21 | requiredMemoryData: MemoryData(littleEndianData: Data([0x48, 0x8D, 0x35, 0x0C, 0x4C, 0x00, 0x00]))), 22 | Requirement(addressInExecutableFile: 0x100001c3d, // __CFConstantStringClassReference check 23 | requiredMemoryData: MemoryData(littleEndianData: Data([0x4C, 0x8D, 0x2D, 0xFC, 0x5A, 0x00, 0x00]))), 24 | Requirement(addressInExecutableFile: 0x100001468, // ___stack_chk_guard check 25 | requiredMemoryData: MemoryData(littleEndianData: Data([0x48, 0x8B, 0x05, 0xC9, 0x5B, 0x00, 0x00]))), 26 | Requirement(addressInExecutableFile: 0x100001755, // __stack_chk_fail check 27 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0xDC, 0x37, 0x00, 0x00]))), 28 | Requirement(addressInExecutableFile: 0x100001cfe, // os_log_create check 29 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0xBD, 0x32, 0x00, 0x00]))), 30 | Requirement(addressInExecutableFile: 0x1000014cd, // os_log_type_enabled check 31 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0xF4, 0x3A, 0x00, 0x00]))), 32 | Requirement(addressInExecutableFile: 0x10000192b, // _os_log_impl check 33 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0x18, 0x36, 0x00, 0x00]))), 34 | Requirement(addressInExecutableFile: 0x100001525, // _os_log_error_impl check 35 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0x12, 0x3A, 0x00, 0x00]))), 36 | Requirement(addressInExecutableFile: 0x100002814, // dispatch_once check 37 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0x53, 0x27, 0x00, 0x00]))), 38 | Requirement(addressInExecutableFile: 0x100001f0c, // SecRequirementCreateWithString check 39 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0xF5, 0x2F, 0x00, 0x00]))), 40 | Requirement(addressInExecutableFile: 0x100001f87, // SecStaticCodeCheckValidityWithErrors check 41 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0x86, 0x2F, 0x00, 0x00]))), 42 | Requirement(addressInExecutableFile: 0x1000016ec, // CFRelease check 43 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0xA3, 0x37, 0x00, 0x00]))), 44 | Requirement(addressInExecutableFile: 0x100003157, // sub_10000435f check 45 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0x03, 0x12, 0x00, 0x00])))], 46 | target: MemoryData(littleEndianData: Data(repeating: 0, count: 0x508)), 47 | replacement: InjectedCode(memoryData: MemoryData(littleEndianData: Data([0x55, 0x48, 0x89, 0xE5, 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, 0x41, 0x54, 0x53, 0x48, 0x83, 0xEC, 0x28, 0x49, 0x89, 0xCF, 0x49, 0x89, 0xD4, 0x49, 0x89, 0xF5, 0x48, 0x89, 0x7D, 0xC8, 0x48, 0x8B, 0x05, 0x33, 0xF5, 0xFF, 0xFF, 0x48, 0x8B, 0x00, 0x48, 0x89, 0x45, 0xD0, 0x48, 0x83, 0x3D, 0xCC, 0x04, 0x00, 0x00, 0xFF, 0x0F, 0x85, 0x22, 0x02, 0x00, 0x00, 0x48, 0x8B, 0x1D, 0xB7, 0x04, 0x00, 0x00, 0x31, 0xF6, 0x48, 0x89, 0xDF, 0xE8, 0x9B, 0xD4, 0xFF, 0xFF, 0x84, 0xC0, 0x74, 0x34, 0x49, 0x89, 0xE6, 0x48, 0x89, 0xE0, 0x4C, 0x8D, 0x40, 0xF0, 0x4C, 0x89, 0xC4, 0x66, 0xC7, 0x40, 0xF0, 0x00, 0x00, 0x48, 0x8D, 0x3D, 0xB7, 0x84, 0xFF, 0xFF, 0x48, 0x8D, 0x0D, 0x57, 0x03, 0x00, 0x00, 0x31, 0xD2, 0x41, 0xB9, 0x02, 0x00, 0x00, 0x00, 0x48, 0x89, 0xDE, 0xE8, 0xE8, 0xD3, 0xFF, 0xFF, 0x4C, 0x89, 0xF4, 0x48, 0x8D, 0x55, 0xC0, 0x48, 0xC7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x3D, 0x43, 0x04, 0x00, 0x00, 0x31, 0xF6, 0xE8, 0x8A, 0xD3, 0xFF, 0xFF, 0x41, 0x89, 0xC6, 0x45, 0x85, 0xF6, 0x74, 0x71, 0x48, 0x8B, 0x1D, 0x4D, 0x04, 0x00, 0x00, 0xBE, 0x10, 0x00, 0x00, 0x00, 0x48, 0x89, 0xDF, 0xE8, 0x2E, 0xD4, 0xFF, 0xFF, 0x84, 0xC0, 0x0F, 0x84, 0x20, 0x01, 0x00, 0x00, 0x4C, 0x89, 0x6D, 0xB8, 0x4D, 0x89, 0xE5, 0x4D, 0x89, 0xFC, 0x49, 0x89, 0xE7, 0x48, 0x89, 0xE0, 0x4C, 0x8D, 0x40, 0xF0, 0x4C, 0x89, 0xC4, 0xC7, 0x40, 0xF0, 0x00, 0x01, 0x00, 0x04, 0x44, 0x89, 0x70, 0xF4, 0x48, 0x8D, 0x3D, 0x37, 0x84, 0xFF, 0xFF, 0x48, 0x8D, 0x0D, 0xF7, 0x02, 0x00, 0x00, 0xBA, 0x10, 0x00, 0x00, 0x00, 0x41, 0xB9, 0x08, 0x00, 0x00, 0x00, 0x48, 0x89, 0xDE, 0xE8, 0x59, 0xD3, 0xFF, 0xFF, 0x4C, 0x89, 0xFC, 0x4D, 0x89, 0xE7, 0x4D, 0x89, 0xEC, 0x4C, 0x8B, 0x6D, 0xB8, 0xE9, 0xCB, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x55, 0xC0, 0x31, 0xF6, 0x31, 0xC9, 0x48, 0x8B, 0x7D, 0xC8, 0xE8, 0x0C, 0xD3, 0xFF, 0xFF, 0x89, 0xC3, 0x48, 0x8B, 0x7D, 0xC0, 0xE8, 0x83, 0xD2, 0xFF, 0xFF, 0x85, 0xDB, 0x0F, 0x84, 0xB9, 0x00, 0x00, 0x00, 0x81, 0xFB, 0x16, 0xFA, 0xFE, 0xFF, 0x75, 0x4C, 0x48, 0x8B, 0x1D, 0xB0, 0x03, 0x00, 0x00, 0x31, 0xF6, 0x48, 0x89, 0xDF, 0xE8, 0x94, 0xD3, 0xFF, 0xFF, 0x84, 0xC0, 0x0F, 0x84, 0x86, 0x00, 0x00, 0x00, 0x49, 0x89, 0xE6, 0x48, 0x89, 0xE0, 0x4C, 0x8D, 0x40, 0xF0, 0x4C, 0x89, 0xC4, 0x66, 0xC7, 0x40, 0xF0, 0x00, 0x00, 0x48, 0x8D, 0x3D, 0xAC, 0x83, 0xFF, 0xFF, 0x48, 0x8D, 0x0D, 0x9C, 0x02, 0x00, 0x00, 0x31, 0xD2, 0x41, 0xB9, 0x02, 0x00, 0x00, 0x00, 0x48, 0x89, 0xDE, 0xE8, 0xDD, 0xD2, 0xFF, 0xFF, 0xEB, 0x50, 0x4C, 0x8B, 0x35, 0x64, 0x03, 0x00, 0x00, 0xBE, 0x10, 0x00, 0x00, 0x00, 0x4C, 0x89, 0xF7, 0xE8, 0x45, 0xD3, 0xFF, 0xFF, 0x84, 0xC0, 0x74, 0x3B, 0x4C, 0x89, 0xF6, 0x49, 0x89, 0xE6, 0x48, 0x89, 0xE0, 0x4C, 0x8D, 0x40, 0xF0, 0x4C, 0x89, 0xC4, 0xC7, 0x40, 0xF0, 0x00, 0x01, 0x00, 0x04, 0x89, 0x58, 0xF4, 0x48, 0x8D, 0x3D, 0x5A, 0x83, 0xFF, 0xFF, 0x48, 0x8D, 0x0D, 0x6A, 0x02, 0x00, 0x00, 0xBA, 0x10, 0x00, 0x00, 0x00, 0x41, 0xB9, 0x08, 0x00, 0x00, 0x00, 0xE8, 0x7F, 0xD2, 0xFF, 0xFF, 0x4C, 0x89, 0xF4, 0x48, 0x8B, 0x7D, 0xC8, 0x4C, 0x89, 0xEE, 0x4C, 0x89, 0xE2, 0x4C, 0x89, 0xF9, 0xE8, 0x8D, 0xC6, 0xFF, 0xFF, 0x48, 0x8B, 0x1D, 0xFF, 0x02, 0x00, 0x00, 0x31, 0xF6, 0x48, 0x89, 0xDF, 0xE8, 0xE3, 0xD2, 0xFF, 0xFF, 0x84, 0xC0, 0x74, 0x34, 0x49, 0x89, 0xE6, 0x48, 0x89, 0xE0, 0x4C, 0x8D, 0x40, 0xF0, 0x4C, 0x89, 0xC4, 0x66, 0xC7, 0x40, 0xF0, 0x00, 0x00, 0x48, 0x8D, 0x3D, 0xFF, 0x82, 0xFF, 0xFF, 0x48, 0x8D, 0x0D, 0x4F, 0x02, 0x00, 0x00, 0x31, 0xD2, 0x41, 0xB9, 0x02, 0x00, 0x00, 0x00, 0x48, 0x89, 0xDE, 0xE8, 0x30, 0xD2, 0xFF, 0xFF, 0x4C, 0x89, 0xF4, 0x48, 0x8B, 0x05, 0x16, 0xF3, 0xFF, 0xFF, 0x48, 0x8B, 0x00, 0x48, 0x3B, 0x45, 0xD0, 0x75, 0x29, 0x31, 0xC0, 0x48, 0x8D, 0x65, 0xD8, 0x5B, 0x41, 0x5C, 0x41, 0x5D, 0x41, 0x5E, 0x41, 0x5F, 0x5D, 0xC3, 0x48, 0x8D, 0x3D, 0x9D, 0x02, 0x00, 0x00, 0x48, 0x8D, 0x35, 0x4D, 0x02, 0x00, 0x00, 0xE8, 0x1D, 0xD2, 0xFF, 0xFF, 0xE9, 0xC6, 0xFD, 0xFF, 0xFF, 0xE8, 0xDD, 0xD1, 0xFF, 0xFF, 0x55, 0x48, 0x89, 0xE5, 0x48, 0x8D, 0x3D, 0x1B, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x35, 0x41, 0x00, 0x00, 0x00, 0xE8, 0x50, 0xD2, 0xFF, 0xFF, 0x48, 0x89, 0x05, 0x61, 0x02, 0x00, 0x00, 0x5D, 0xC3, 0x76, 0x38, 0x40, 0x3F, 0x30, 0x00, 0x6D, 0x6F, 0x2E, 0x64, 0x61, 0x72, 0x72, 0x65, 0x6E, 0x2E, 0x6F, 0x70, 0x74, 0x69, 0x6D, 0x75, 0x73, 0x2E, 0x70, 0x6C, 0x61, 0x79, 0x65, 0x72, 0x2E, 0x6D, 0x61, 0x63, 0x2E, 0x61, 0x69, 0x72, 0x70, 0x6C, 0x61, 0x79, 0x2D, 0x65, 0x6E, 0x61, 0x62, 0x6C, 0x65, 0x72, 0x00, 0x49, 0x6E, 0x6A, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x43, 0x6F, 0x64, 0x65, 0x00, 0x61, 0x6E, 0x63, 0x68, 0x6F, 0x72, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x65, 0x20, 0x67, 0x65, 0x6E, 0x65, 0x72, 0x69, 0x63, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x28, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x6C, 0x65, 0x61, 0x66, 0x5B, 0x66, 0x69, 0x65, 0x6C, 0x64, 0x2E, 0x31, 0x2E, 0x32, 0x2E, 0x38, 0x34, 0x30, 0x2E, 0x31, 0x31, 0x33, 0x36, 0x33, 0x35, 0x2E, 0x31, 0x30, 0x30, 0x2E, 0x36, 0x2E, 0x31, 0x2E, 0x39, 0x5D, 0x20, 0x6F, 0x72, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x31, 0x5B, 0x66, 0x69, 0x65, 0x6C, 0x64, 0x2E, 0x31, 0x2E, 0x32, 0x2E, 0x38, 0x34, 0x30, 0x2E, 0x31, 0x31, 0x33, 0x36, 0x33, 0x35, 0x2E, 0x31, 0x30, 0x30, 0x2E, 0x36, 0x2E, 0x32, 0x2E, 0x36, 0x5D, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x6C, 0x65, 0x61, 0x66, 0x5B, 0x66, 0x69, 0x65, 0x6C, 0x64, 0x2E, 0x31, 0x2E, 0x32, 0x2E, 0x38, 0x34, 0x30, 0x2E, 0x31, 0x31, 0x33, 0x36, 0x33, 0x35, 0x2E, 0x31, 0x30, 0x30, 0x2E, 0x36, 0x2E, 0x31, 0x2E, 0x31, 0x33, 0x5D, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x6C, 0x65, 0x61, 0x66, 0x5B, 0x73, 0x75, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x2E, 0x4F, 0x55, 0x5D, 0x20, 0x3D, 0x20, 0x50, 0x56, 0x4C, 0x51, 0x34, 0x39, 0x4C, 0x41, 0x48, 0x33, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x74, 0x61, 0x72, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x69, 0x6E, 0x6A, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6F, 0x64, 0x65, 0x2E, 0x00, 0x00, 0x46, 0x61, 0x69, 0x6C, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x3A, 0x20, 0x25, 0x64, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x6F, 0x64, 0x65, 0x20, 0x64, 0x6F, 0x65, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x6D, 0x65, 0x65, 0x74, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x2E, 0x00, 0x46, 0x61, 0x69, 0x6C, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6B, 0x20, 0x77, 0x68, 0x65, 0x74, 0x68, 0x65, 0x72, 0x20, 0x63, 0x6F, 0x64, 0x65, 0x20, 0x6D, 0x65, 0x65, 0x74, 0x73, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x3A, 0x20, 0x25, 0x64, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x69, 0x6E, 0x69, 0x73, 0x68, 0x65, 0x64, 0x20, 0x72, 0x75, 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x6E, 0x6A, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6F, 0x64, 0x65, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x7D, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB8, 0xD1, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x59, 0x7D, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x77, 0x7F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xC8, 0xD1, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xC8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBA, 0x7D, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])), 48 | absoluteAddressRanges: [0x4a7..<0x4af, // __block_descriptor_tmp 49 | 0x4c7..<0x4cf, // __block_literal_global 50 | 0x4cf..<0x4d7, 51 | 0x4e8..<0x4f0], // cfstring_anchor_apple_generic_and__certificate_leaf_field_1_2_840_113635_100_6_1_9__or_certificate_1 52 | externalSymbolInfos: [InjectedCode.ExternalSymbolInfo(absoluteAddressRange: 0x4b7..<0x4bf, // External Symbol: _NSConcreteGlobalBlock 53 | replaceWithPointerValueAt: 0x1000073c0), 54 | InjectedCode.ExternalSymbolInfo(absoluteAddressRange: 0x4d8..<0x4e0, // External Symbol: __CFConstantStringClassReference 55 | replaceWithPointerValueAt: 0x100007740)], 56 | writableRanges: [0x497..<0x4a7, // __block_descriptor_tmp 57 | 0x4af..<0x4b7, 58 | 0x4bf..<0x4c7, // __block_literal_global 59 | 0x4f8..<0x500, // _RunInjectedCode.log 60 | 0x500..<0x508]), // _RunInjectedCode.onceToken 61 | originalMemoryProtection: VM_PROT_READ | VM_PROT_WRITE) 62 | } 63 | 64 | private static func makeFunctionCallPatch() -> Patch { 65 | // Replaces `call sub_10000435f` with `call _RunInjectedCode`. 66 | // The requirements ensure that the arguments to the call are what we expect. 67 | return Patch(addressInExecutableFile: 0x100003157, 68 | requirements: [Requirement(addressInExecutableFile: 0x100003142, 69 | requiredMemoryData: MemoryData(littleEndianData: Data([0x48, 0x8B, 0x4D, 0x30, 0x48, 0x8D, 0x55, 0x88, 0xC7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x7D, 0xC8, 0x4C, 0x89, 0xF6])))], 70 | target: MemoryData(littleEndianData: Data([0xE8, 0x03, 0x12, 0x00, 0x00])), 71 | replacement: InjectedCode(memoryData: MemoryData(littleEndianData: Data([0xE8, 0x84, 0x49, 0x00, 0x00]))), 72 | originalMemoryProtection: VM_PROT_READ | VM_PROT_EXECUTE) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /AirPlayEnabler/Code Injection/Patches/Patch+MacOS10_14_4.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Patch+MacOS10_14_4.swift 3 | // AirPlayEnabler 4 | // 5 | // Created by Darren Mo on 2019-04-12. 6 | // Copyright © 2019 Darren Mo. All rights reserved. 7 | // 8 | 9 | extension Patch { 10 | static func makePatchesForMacOS10_14_4() -> [Patch] { 11 | return [ 12 | makeInjectedCodePatch(), 13 | makeFunctionCallPatch() 14 | ] 15 | } 16 | 17 | private static func makeInjectedCodePatch() -> Patch { 18 | // c.f. "Injected Code/macOS 10.14.4/". 19 | return Patch(addressInExecutableFile: 0x100007af8, 20 | requirements: [Requirement(addressInExecutableFile: 0x100002908, // _NSConcreteGlobalBlock check 21 | requiredMemoryData: MemoryData(littleEndianData: Data([0x48, 0x8D, 0x35, 0xC9, 0x4A, 0x00, 0x00]))), 22 | Requirement(addressInExecutableFile: 0x100001e36, // __CFConstantStringClassReference check 23 | requiredMemoryData: MemoryData(littleEndianData: Data([0x4C, 0x8D, 0x2D, 0x13, 0x59, 0x00, 0x00]))), 24 | Requirement(addressInExecutableFile: 0x1000016b9, // ___stack_chk_guard check 25 | requiredMemoryData: MemoryData(littleEndianData: Data([0x48, 0x8B, 0x05, 0x78, 0x59, 0x00, 0x00]))), 26 | Requirement(addressInExecutableFile: 0x100001998, // __stack_chk_fail check 27 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0x81, 0x35, 0x00, 0x00]))), 28 | Requirement(addressInExecutableFile: 0x100001ef7, // os_log_create check 29 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0xAC, 0x30, 0x00, 0x00]))), 30 | Requirement(addressInExecutableFile: 0x100001715, // os_log_type_enabled check 31 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0x94, 0x38, 0x00, 0x00]))), 32 | Requirement(addressInExecutableFile: 0x100001b56, // _os_log_impl check 33 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0xD5, 0x33, 0x00, 0x00]))), 34 | Requirement(addressInExecutableFile: 0x100001763, // _os_log_error_impl check 35 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0xBC, 0x37, 0x00, 0x00]))), 36 | Requirement(addressInExecutableFile: 0x10000296f, // dispatch_once check 37 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0xE0, 0x25, 0x00, 0x00]))), 38 | Requirement(addressInExecutableFile: 0x100002105, // SecRequirementCreateWithString check 39 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0xE4, 0x2D, 0x00, 0x00]))), 40 | Requirement(addressInExecutableFile: 0x100002172, // SecStaticCodeCheckValidityWithErrors check 41 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0x83, 0x2D, 0x00, 0x00]))), 42 | Requirement(addressInExecutableFile: 0x10000192f, // CFRelease check 43 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0x48, 0x35, 0x00, 0x00]))), 44 | Requirement(addressInExecutableFile: 0x10000328f, // sub_10000436b check 45 | requiredMemoryData: MemoryData(littleEndianData: Data([0xE8, 0xD7, 0x10, 0x00, 0x00])))], 46 | target: MemoryData(littleEndianData: Data(repeating: 0, count: 0x508)), 47 | replacement: InjectedCode(memoryData: MemoryData(littleEndianData: Data([0x55, 0x48, 0x89, 0xE5, 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, 0x41, 0x54, 0x53, 0x48, 0x83, 0xEC, 0x28, 0x49, 0x89, 0xCF, 0x49, 0x89, 0xD4, 0x49, 0x89, 0xF5, 0x48, 0x89, 0x7D, 0xC8, 0x48, 0x8B, 0x05, 0x1B, 0xF5, 0xFF, 0xFF, 0x48, 0x8B, 0x00, 0x48, 0x89, 0x45, 0xD0, 0x48, 0x83, 0x3D, 0xCC, 0x04, 0x00, 0x00, 0xFF, 0x0F, 0x85, 0x22, 0x02, 0x00, 0x00, 0x48, 0x8B, 0x1D, 0xB7, 0x04, 0x00, 0x00, 0x31, 0xF6, 0x48, 0x89, 0xDF, 0xE8, 0x6B, 0xD4, 0xFF, 0xFF, 0x84, 0xC0, 0x74, 0x34, 0x49, 0x89, 0xE6, 0x48, 0x89, 0xE0, 0x4C, 0x8D, 0x40, 0xF0, 0x4C, 0x89, 0xC4, 0x66, 0xC7, 0x40, 0xF0, 0x00, 0x00, 0x48, 0x8D, 0x3D, 0x9F, 0x84, 0xFF, 0xFF, 0x48, 0x8D, 0x0D, 0x57, 0x03, 0x00, 0x00, 0x31, 0xD2, 0x41, 0xB9, 0x02, 0x00, 0x00, 0x00, 0x48, 0x89, 0xDE, 0xE8, 0xB8, 0xD3, 0xFF, 0xFF, 0x4C, 0x89, 0xF4, 0x48, 0x8D, 0x55, 0xC0, 0x48, 0xC7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x3D, 0x43, 0x04, 0x00, 0x00, 0x31, 0xF6, 0xE8, 0x5A, 0xD3, 0xFF, 0xFF, 0x41, 0x89, 0xC6, 0x45, 0x85, 0xF6, 0x74, 0x71, 0x48, 0x8B, 0x1D, 0x4D, 0x04, 0x00, 0x00, 0xBE, 0x10, 0x00, 0x00, 0x00, 0x48, 0x89, 0xDF, 0xE8, 0xFE, 0xD3, 0xFF, 0xFF, 0x84, 0xC0, 0x0F, 0x84, 0x20, 0x01, 0x00, 0x00, 0x4C, 0x89, 0x6D, 0xB8, 0x4D, 0x89, 0xE5, 0x4D, 0x89, 0xFC, 0x49, 0x89, 0xE7, 0x48, 0x89, 0xE0, 0x4C, 0x8D, 0x40, 0xF0, 0x4C, 0x89, 0xC4, 0xC7, 0x40, 0xF0, 0x00, 0x01, 0x00, 0x04, 0x44, 0x89, 0x70, 0xF4, 0x48, 0x8D, 0x3D, 0x1F, 0x84, 0xFF, 0xFF, 0x48, 0x8D, 0x0D, 0xF7, 0x02, 0x00, 0x00, 0xBA, 0x10, 0x00, 0x00, 0x00, 0x41, 0xB9, 0x08, 0x00, 0x00, 0x00, 0x48, 0x89, 0xDE, 0xE8, 0x29, 0xD3, 0xFF, 0xFF, 0x4C, 0x89, 0xFC, 0x4D, 0x89, 0xE7, 0x4D, 0x89, 0xEC, 0x4C, 0x8B, 0x6D, 0xB8, 0xE9, 0xCB, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x55, 0xC0, 0x31, 0xF6, 0x31, 0xC9, 0x48, 0x8B, 0x7D, 0xC8, 0xE8, 0xDC, 0xD2, 0xFF, 0xFF, 0x89, 0xC3, 0x48, 0x8B, 0x7D, 0xC0, 0xE8, 0x53, 0xD2, 0xFF, 0xFF, 0x85, 0xDB, 0x0F, 0x84, 0xB9, 0x00, 0x00, 0x00, 0x81, 0xFB, 0x16, 0xFA, 0xFE, 0xFF, 0x75, 0x4C, 0x48, 0x8B, 0x1D, 0xB0, 0x03, 0x00, 0x00, 0x31, 0xF6, 0x48, 0x89, 0xDF, 0xE8, 0x64, 0xD3, 0xFF, 0xFF, 0x84, 0xC0, 0x0F, 0x84, 0x86, 0x00, 0x00, 0x00, 0x49, 0x89, 0xE6, 0x48, 0x89, 0xE0, 0x4C, 0x8D, 0x40, 0xF0, 0x4C, 0x89, 0xC4, 0x66, 0xC7, 0x40, 0xF0, 0x00, 0x00, 0x48, 0x8D, 0x3D, 0x94, 0x83, 0xFF, 0xFF, 0x48, 0x8D, 0x0D, 0x9C, 0x02, 0x00, 0x00, 0x31, 0xD2, 0x41, 0xB9, 0x02, 0x00, 0x00, 0x00, 0x48, 0x89, 0xDE, 0xE8, 0xAD, 0xD2, 0xFF, 0xFF, 0xEB, 0x50, 0x4C, 0x8B, 0x35, 0x64, 0x03, 0x00, 0x00, 0xBE, 0x10, 0x00, 0x00, 0x00, 0x4C, 0x89, 0xF7, 0xE8, 0x15, 0xD3, 0xFF, 0xFF, 0x84, 0xC0, 0x74, 0x3B, 0x4C, 0x89, 0xF6, 0x49, 0x89, 0xE6, 0x48, 0x89, 0xE0, 0x4C, 0x8D, 0x40, 0xF0, 0x4C, 0x89, 0xC4, 0xC7, 0x40, 0xF0, 0x00, 0x01, 0x00, 0x04, 0x89, 0x58, 0xF4, 0x48, 0x8D, 0x3D, 0x42, 0x83, 0xFF, 0xFF, 0x48, 0x8D, 0x0D, 0x6A, 0x02, 0x00, 0x00, 0xBA, 0x10, 0x00, 0x00, 0x00, 0x41, 0xB9, 0x08, 0x00, 0x00, 0x00, 0xE8, 0x4F, 0xD2, 0xFF, 0xFF, 0x4C, 0x89, 0xF4, 0x48, 0x8B, 0x7D, 0xC8, 0x4C, 0x89, 0xEE, 0x4C, 0x89, 0xE2, 0x4C, 0x89, 0xF9, 0xE8, 0x81, 0xC6, 0xFF, 0xFF, 0x48, 0x8B, 0x1D, 0xFF, 0x02, 0x00, 0x00, 0x31, 0xF6, 0x48, 0x89, 0xDF, 0xE8, 0xB3, 0xD2, 0xFF, 0xFF, 0x84, 0xC0, 0x74, 0x34, 0x49, 0x89, 0xE6, 0x48, 0x89, 0xE0, 0x4C, 0x8D, 0x40, 0xF0, 0x4C, 0x89, 0xC4, 0x66, 0xC7, 0x40, 0xF0, 0x00, 0x00, 0x48, 0x8D, 0x3D, 0xE7, 0x82, 0xFF, 0xFF, 0x48, 0x8D, 0x0D, 0x4F, 0x02, 0x00, 0x00, 0x31, 0xD2, 0x41, 0xB9, 0x02, 0x00, 0x00, 0x00, 0x48, 0x89, 0xDE, 0xE8, 0x00, 0xD2, 0xFF, 0xFF, 0x4C, 0x89, 0xF4, 0x48, 0x8B, 0x05, 0xFE, 0xF2, 0xFF, 0xFF, 0x48, 0x8B, 0x00, 0x48, 0x3B, 0x45, 0xD0, 0x75, 0x29, 0x31, 0xC0, 0x48, 0x8D, 0x65, 0xD8, 0x5B, 0x41, 0x5C, 0x41, 0x5D, 0x41, 0x5E, 0x41, 0x5F, 0x5D, 0xC3, 0x48, 0x8D, 0x3D, 0x9D, 0x02, 0x00, 0x00, 0x48, 0x8D, 0x35, 0x4D, 0x02, 0x00, 0x00, 0xE8, 0xED, 0xD1, 0xFF, 0xFF, 0xE9, 0xC6, 0xFD, 0xFF, 0xFF, 0xE8, 0xAD, 0xD1, 0xFF, 0xFF, 0x55, 0x48, 0x89, 0xE5, 0x48, 0x8D, 0x3D, 0x1B, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x35, 0x41, 0x00, 0x00, 0x00, 0xE8, 0x20, 0xD2, 0xFF, 0xFF, 0x48, 0x89, 0x05, 0x61, 0x02, 0x00, 0x00, 0x5D, 0xC3, 0x76, 0x38, 0x40, 0x3F, 0x30, 0x00, 0x6D, 0x6F, 0x2E, 0x64, 0x61, 0x72, 0x72, 0x65, 0x6E, 0x2E, 0x6F, 0x70, 0x74, 0x69, 0x6D, 0x75, 0x73, 0x2E, 0x70, 0x6C, 0x61, 0x79, 0x65, 0x72, 0x2E, 0x6D, 0x61, 0x63, 0x2E, 0x61, 0x69, 0x72, 0x70, 0x6C, 0x61, 0x79, 0x2D, 0x65, 0x6E, 0x61, 0x62, 0x6C, 0x65, 0x72, 0x00, 0x49, 0x6E, 0x6A, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x43, 0x6F, 0x64, 0x65, 0x00, 0x61, 0x6E, 0x63, 0x68, 0x6F, 0x72, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x65, 0x20, 0x67, 0x65, 0x6E, 0x65, 0x72, 0x69, 0x63, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x28, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x6C, 0x65, 0x61, 0x66, 0x5B, 0x66, 0x69, 0x65, 0x6C, 0x64, 0x2E, 0x31, 0x2E, 0x32, 0x2E, 0x38, 0x34, 0x30, 0x2E, 0x31, 0x31, 0x33, 0x36, 0x33, 0x35, 0x2E, 0x31, 0x30, 0x30, 0x2E, 0x36, 0x2E, 0x31, 0x2E, 0x39, 0x5D, 0x20, 0x6F, 0x72, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x31, 0x5B, 0x66, 0x69, 0x65, 0x6C, 0x64, 0x2E, 0x31, 0x2E, 0x32, 0x2E, 0x38, 0x34, 0x30, 0x2E, 0x31, 0x31, 0x33, 0x36, 0x33, 0x35, 0x2E, 0x31, 0x30, 0x30, 0x2E, 0x36, 0x2E, 0x32, 0x2E, 0x36, 0x5D, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x6C, 0x65, 0x61, 0x66, 0x5B, 0x66, 0x69, 0x65, 0x6C, 0x64, 0x2E, 0x31, 0x2E, 0x32, 0x2E, 0x38, 0x34, 0x30, 0x2E, 0x31, 0x31, 0x33, 0x36, 0x33, 0x35, 0x2E, 0x31, 0x30, 0x30, 0x2E, 0x36, 0x2E, 0x31, 0x2E, 0x31, 0x33, 0x5D, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x6C, 0x65, 0x61, 0x66, 0x5B, 0x73, 0x75, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x2E, 0x4F, 0x55, 0x5D, 0x20, 0x3D, 0x20, 0x50, 0x56, 0x4C, 0x51, 0x34, 0x39, 0x4C, 0x41, 0x48, 0x33, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x74, 0x61, 0x72, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x69, 0x6E, 0x6A, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6F, 0x64, 0x65, 0x2E, 0x00, 0x00, 0x46, 0x61, 0x69, 0x6C, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x3A, 0x20, 0x25, 0x64, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x6F, 0x64, 0x65, 0x20, 0x64, 0x6F, 0x65, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x6D, 0x65, 0x65, 0x74, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x2E, 0x00, 0x46, 0x61, 0x69, 0x6C, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6B, 0x20, 0x77, 0x68, 0x65, 0x74, 0x68, 0x65, 0x72, 0x20, 0x63, 0x6F, 0x64, 0x65, 0x20, 0x6D, 0x65, 0x65, 0x74, 0x73, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x3A, 0x20, 0x25, 0x64, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x69, 0x6E, 0x69, 0x73, 0x68, 0x65, 0x64, 0x20, 0x72, 0x75, 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x6E, 0x6A, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6F, 0x64, 0x65, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x7D, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB8, 0xD1, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x71, 0x7D, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x8F, 0x7F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xC8, 0xD1, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xC8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD2, 0x7D, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])), 48 | absoluteAddressRanges: [0x4a7..<0x4af, // __block_descriptor_tmp 49 | 0x4c7..<0x4cf, // __block_literal_global 50 | 0x4cf..<0x4d7, 51 | 0x4e8..<0x4f0], // cfstring_anchor_apple_generic_and__certificate_leaf_field_1_2_840_113635_100_6_1_9__or_certificate_1 52 | externalSymbolInfos: [InjectedCode.ExternalSymbolInfo(absoluteAddressRange: 0x4b7..<0x4bf, // External Symbol: _NSConcreteGlobalBlock 53 | replaceWithPointerValueAt: 0x1000073d8), 54 | InjectedCode.ExternalSymbolInfo(absoluteAddressRange: 0x4d8..<0x4e0, // External Symbol: __CFConstantStringClassReference 55 | replaceWithPointerValueAt: 0x100007750)], 56 | writableRanges: [0x497..<0x4a7, // __block_descriptor_tmp 57 | 0x4af..<0x4b7, 58 | 0x4bf..<0x4c7, // __block_literal_global 59 | 0x4f8..<0x500, // _RunInjectedCode.log 60 | 0x500..<0x508]), // _RunInjectedCode.onceToken 61 | originalMemoryProtection: VM_PROT_READ | VM_PROT_WRITE) 62 | } 63 | 64 | private static func makeFunctionCallPatch() -> Patch { 65 | // Replaces `call sub_10000436b` with `call _RunInjectedCode`. 66 | // The requirements ensure that the arguments to the call are what we expect. 67 | return Patch(addressInExecutableFile: 0x10000328f, 68 | requirements: [Requirement(addressInExecutableFile: 0x100003277, 69 | requiredMemoryData: MemoryData(littleEndianData: Data([0x48, 0x8B, 0x4D, 0x30, 0x48, 0x8D, 0x95, 0x7C, 0xFF, 0xFF, 0xFF, 0xC7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x7D, 0x98, 0x4C, 0x89, 0xF6])))], 70 | target: MemoryData(littleEndianData: Data([0xE8, 0xD7, 0x10, 0x00, 0x00])), 71 | replacement: InjectedCode(memoryData: MemoryData(littleEndianData: Data([0xE8, 0x64, 0x48, 0x00, 0x00]))), 72 | originalMemoryProtection: VM_PROT_READ | VM_PROT_EXECUTE) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /AirPlayEnabler.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | E65DDE9021C0679D00FB35E4 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65DDE8F21C0679D00FB35E4 /* main.swift */; }; 11 | E65DDEB021C1F2A500FB35E4 /* CodeInjector.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65DDEAF21C1F2A500FB35E4 /* CodeInjector.swift */; }; 12 | E667BBFD21CD73DE00FB35E4 /* Patch.swift in Sources */ = {isa = PBXBuildFile; fileRef = E667BBFC21CD73DE00FB35E4 /* Patch.swift */; }; 13 | E667BBFF21CD745F00FB35E4 /* MemoryData.swift in Sources */ = {isa = PBXBuildFile; fileRef = E667BBFE21CD745F00FB35E4 /* MemoryData.swift */; }; 14 | E667BC0321CD7E2200FB35E4 /* ExecutableInfo+AddressInTaskSpace.swift in Sources */ = {isa = PBXBuildFile; fileRef = E667BC0221CD7E2200FB35E4 /* ExecutableInfo+AddressInTaskSpace.swift */; }; 15 | E667BC0521CDC41A00FB35E4 /* Patch+DynamicCreation.swift in Sources */ = {isa = PBXBuildFile; fileRef = E667BC0421CDC41A00FB35E4 /* Patch+DynamicCreation.swift */; }; 16 | E667BC0A21CDC51400FB35E4 /* Patch+MacOS10_14.swift in Sources */ = {isa = PBXBuildFile; fileRef = E667BC0921CDC51400FB35E4 /* Patch+MacOS10_14.swift */; }; 17 | E667BC0C21CDCB4A00FB35E4 /* Patch+Requirement.swift in Sources */ = {isa = PBXBuildFile; fileRef = E667BC0B21CDCB4A00FB35E4 /* Patch+Requirement.swift */; }; 18 | E67FBFD721D0105A00FB35E4 /* ImageInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = E67FBFD521D0105A00FB35E4 /* ImageInfo.m */; }; 19 | E67FBFDA21D010F000FB35E4 /* Common.m in Sources */ = {isa = PBXBuildFile; fileRef = E67FBFD821D010F000FB35E4 /* Common.m */; }; 20 | E688AE5321C8AD5500FB35E4 /* XPCService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E688AE5221C8AD5500FB35E4 /* XPCService.swift */; }; 21 | E688AE5721C9637B00FB35E4 /* XPCServiceImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = E688AE5621C9637B00FB35E4 /* XPCServiceImplementation.swift */; }; 22 | E688AE6521C9775D00FB35E4 /* AirPlayEnablerInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = E688AE5421C960FB00FB35E4 /* AirPlayEnablerInterface.swift */; }; 23 | E688AE7321C97DFF00FB35E4 /* libAirPlayEnablerInterface.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E688AE5C21C9774B00FB35E4 /* libAirPlayEnablerInterface.a */; }; 24 | E688AE7521C97F2400FB35E4 /* AirPlayEnablerInterfaceError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E688AE7421C97F2400FB35E4 /* AirPlayEnablerInterfaceError.swift */; }; 25 | E688AE7821C9AE1100FB35E4 /* PrivilegedHelperInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E688AE7721C9AE1100FB35E4 /* PrivilegedHelperInfo.swift */; }; 26 | E688AE7A21C9B84A00FB35E4 /* XPCServiceImplementation+UninstallPrivilegedHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E688AE7921C9B84A00FB35E4 /* XPCServiceImplementation+UninstallPrivilegedHelper.swift */; }; 27 | E69310752261544700FB35E4 /* Patch+MacOS10_14_4.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69310742261544700FB35E4 /* Patch+MacOS10_14_4.swift */; }; 28 | E69A58C421CACFC600FB35E4 /* XPCServiceImplementation+IsPrivilegedHelperRunning.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69A58C321CACFC500FB35E4 /* XPCServiceImplementation+IsPrivilegedHelperRunning.swift */; }; 29 | E6B1F2B221C1FD7E00FB35E4 /* ExecutableInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = E6B1F2B121C1FD7E00FB35E4 /* ExecutableInfo.m */; }; 30 | E6B1F2BC21C4A39900FB35E4 /* ExecutableInfo+ByteOrder.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6B1F2BB21C4A39900FB35E4 /* ExecutableInfo+ByteOrder.swift */; }; 31 | E6B1F2BF21C5C33B00FB35E4 /* ActivityTracing.m in Sources */ = {isa = PBXBuildFile; fileRef = E6B1F2BE21C5C33B00FB35E4 /* ActivityTracing.m */; }; 32 | E6D4062921D0AFCD00FB35E4 /* Data+TaskVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6D4062821D0AFCD00FB35E4 /* Data+TaskVM.swift */; }; 33 | E6D4062B21D1F9C700FB35E4 /* InjectedCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6D4062A21D1F9C700FB35E4 /* InjectedCode.swift */; }; 34 | E6D4062D21D2D5FE00FB35E4 /* InjectedCode+Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6D4062C21D2D5FE00FB35E4 /* InjectedCode+Data.swift */; }; 35 | E6D4062F21D2D61900FB35E4 /* InjectedCode+ExternalSymbolInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6D4062E21D2D61900FB35E4 /* InjectedCode+ExternalSymbolInfo.swift */; }; 36 | E6D4063521D3390400FB35E4 /* ActivityTracing.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6D4063421D3390400FB35E4 /* ActivityTracing.swift */; }; 37 | E6FAA06421CC269200FB35E4 /* PrivilegedHelperVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6FAA06321CC269200FB35E4 /* PrivilegedHelperVersion.swift */; }; 38 | E6FAA06621CC28EA00FB35E4 /* XPCServiceImplementation+GetPrivilegedHelperVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6FAA06521CC28EA00FB35E4 /* XPCServiceImplementation+GetPrivilegedHelperVersion.swift */; }; 39 | /* End PBXBuildFile section */ 40 | 41 | /* Begin PBXContainerItemProxy section */ 42 | E688AE6621C977AC00FB35E4 /* PBXContainerItemProxy */ = { 43 | isa = PBXContainerItemProxy; 44 | containerPortal = E65DDE8421C0679D00FB35E4 /* Project object */; 45 | proxyType = 1; 46 | remoteGlobalIDString = E688AE5B21C9774B00FB35E4; 47 | remoteInfo = AirPlayEnablerInterface; 48 | }; 49 | /* End PBXContainerItemProxy section */ 50 | 51 | /* Begin PBXCopyFilesBuildPhase section */ 52 | E65DDE8A21C0679D00FB35E4 /* CopyFiles */ = { 53 | isa = PBXCopyFilesBuildPhase; 54 | buildActionMask = 2147483647; 55 | dstPath = /usr/share/man/man1/; 56 | dstSubfolderSpec = 0; 57 | files = ( 58 | ); 59 | runOnlyForDeploymentPostprocessing = 1; 60 | }; 61 | /* End PBXCopyFilesBuildPhase section */ 62 | 63 | /* Begin PBXFileReference section */ 64 | E65DDE8C21C0679D00FB35E4 /* mo.darren.optimus.player.mac.airplay-enabler */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "mo.darren.optimus.player.mac.airplay-enabler"; sourceTree = BUILT_PRODUCTS_DIR; }; 65 | E65DDE8F21C0679D00FB35E4 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 66 | E65DDE9D21C0684C00FB35E4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 67 | E65DDE9E21C06A8B00FB35E4 /* Launchd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Launchd.plist; sourceTree = ""; }; 68 | E65DDEAF21C1F2A500FB35E4 /* CodeInjector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeInjector.swift; sourceTree = ""; }; 69 | E667BBFC21CD73DE00FB35E4 /* Patch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Patch.swift; sourceTree = ""; }; 70 | E667BBFE21CD745F00FB35E4 /* MemoryData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryData.swift; sourceTree = ""; }; 71 | E667BC0221CD7E2200FB35E4 /* ExecutableInfo+AddressInTaskSpace.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ExecutableInfo+AddressInTaskSpace.swift"; sourceTree = ""; }; 72 | E667BC0421CDC41A00FB35E4 /* Patch+DynamicCreation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Patch+DynamicCreation.swift"; sourceTree = ""; }; 73 | E667BC0921CDC51400FB35E4 /* Patch+MacOS10_14.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Patch+MacOS10_14.swift"; sourceTree = ""; }; 74 | E667BC0B21CDCB4A00FB35E4 /* Patch+Requirement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Patch+Requirement.swift"; sourceTree = ""; }; 75 | E67FBFD521D0105A00FB35E4 /* ImageInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ImageInfo.m; sourceTree = ""; }; 76 | E67FBFD621D0105A00FB35E4 /* ImageInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageInfo.h; sourceTree = ""; }; 77 | E67FBFD821D010F000FB35E4 /* Common.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Common.m; sourceTree = ""; }; 78 | E67FBFD921D010F000FB35E4 /* Common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Common.h; sourceTree = ""; }; 79 | E688AE5221C8AD5500FB35E4 /* XPCService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XPCService.swift; sourceTree = ""; }; 80 | E688AE5421C960FB00FB35E4 /* AirPlayEnablerInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AirPlayEnablerInterface.swift; sourceTree = ""; }; 81 | E688AE5621C9637B00FB35E4 /* XPCServiceImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XPCServiceImplementation.swift; sourceTree = ""; }; 82 | E688AE5C21C9774B00FB35E4 /* libAirPlayEnablerInterface.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libAirPlayEnablerInterface.a; sourceTree = BUILT_PRODUCTS_DIR; }; 83 | E688AE7421C97F2400FB35E4 /* AirPlayEnablerInterfaceError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AirPlayEnablerInterfaceError.swift; sourceTree = ""; }; 84 | E688AE7721C9AE1100FB35E4 /* PrivilegedHelperInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivilegedHelperInfo.swift; sourceTree = ""; }; 85 | E688AE7921C9B84A00FB35E4 /* XPCServiceImplementation+UninstallPrivilegedHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XPCServiceImplementation+UninstallPrivilegedHelper.swift"; sourceTree = ""; }; 86 | E69310742261544700FB35E4 /* Patch+MacOS10_14_4.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Patch+MacOS10_14_4.swift"; sourceTree = ""; }; 87 | E69A58C321CACFC500FB35E4 /* XPCServiceImplementation+IsPrivilegedHelperRunning.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "XPCServiceImplementation+IsPrivilegedHelperRunning.swift"; sourceTree = ""; }; 88 | E6B1F2B021C1FD7E00FB35E4 /* AirPlayEnabler-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AirPlayEnabler-Bridging-Header.h"; sourceTree = ""; }; 89 | E6B1F2B121C1FD7E00FB35E4 /* ExecutableInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExecutableInfo.m; sourceTree = ""; }; 90 | E6B1F2B321C1FD9A00FB35E4 /* ExecutableInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ExecutableInfo.h; sourceTree = ""; }; 91 | E6B1F2BB21C4A39900FB35E4 /* ExecutableInfo+ByteOrder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ExecutableInfo+ByteOrder.swift"; sourceTree = ""; }; 92 | E6B1F2BD21C5C33B00FB35E4 /* ActivityTracing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ActivityTracing.h; sourceTree = ""; }; 93 | E6B1F2BE21C5C33B00FB35E4 /* ActivityTracing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ActivityTracing.m; sourceTree = ""; }; 94 | E6D4062821D0AFCD00FB35E4 /* Data+TaskVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+TaskVM.swift"; sourceTree = ""; }; 95 | E6D4062A21D1F9C700FB35E4 /* InjectedCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InjectedCode.swift; sourceTree = ""; }; 96 | E6D4062C21D2D5FE00FB35E4 /* InjectedCode+Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InjectedCode+Data.swift"; sourceTree = ""; }; 97 | E6D4062E21D2D61900FB35E4 /* InjectedCode+ExternalSymbolInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InjectedCode+ExternalSymbolInfo.swift"; sourceTree = ""; }; 98 | E6D4063421D3390400FB35E4 /* ActivityTracing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityTracing.swift; sourceTree = ""; }; 99 | E6FAA06321CC269200FB35E4 /* PrivilegedHelperVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivilegedHelperVersion.swift; sourceTree = ""; }; 100 | E6FAA06521CC28EA00FB35E4 /* XPCServiceImplementation+GetPrivilegedHelperVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XPCServiceImplementation+GetPrivilegedHelperVersion.swift"; sourceTree = ""; }; 101 | /* End PBXFileReference section */ 102 | 103 | /* Begin PBXFrameworksBuildPhase section */ 104 | E65DDE8921C0679D00FB35E4 /* Frameworks */ = { 105 | isa = PBXFrameworksBuildPhase; 106 | buildActionMask = 2147483647; 107 | files = ( 108 | E688AE7321C97DFF00FB35E4 /* libAirPlayEnablerInterface.a in Frameworks */, 109 | ); 110 | runOnlyForDeploymentPostprocessing = 0; 111 | }; 112 | E688AE5A21C9774B00FB35E4 /* Frameworks */ = { 113 | isa = PBXFrameworksBuildPhase; 114 | buildActionMask = 2147483647; 115 | files = ( 116 | ); 117 | runOnlyForDeploymentPostprocessing = 0; 118 | }; 119 | /* End PBXFrameworksBuildPhase section */ 120 | 121 | /* Begin PBXGroup section */ 122 | E65DDE8321C0679D00FB35E4 = { 123 | isa = PBXGroup; 124 | children = ( 125 | E65DDE8E21C0679D00FB35E4 /* AirPlayEnabler */, 126 | E688AE5D21C9774B00FB35E4 /* AirPlayEnablerInterface */, 127 | E65DDE8D21C0679D00FB35E4 /* Products */, 128 | ); 129 | sourceTree = ""; 130 | }; 131 | E65DDE8D21C0679D00FB35E4 /* Products */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | E65DDE8C21C0679D00FB35E4 /* mo.darren.optimus.player.mac.airplay-enabler */, 135 | E688AE5C21C9774B00FB35E4 /* libAirPlayEnablerInterface.a */, 136 | ); 137 | name = Products; 138 | sourceTree = ""; 139 | }; 140 | E65DDE8E21C0679D00FB35E4 /* AirPlayEnabler */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | E65DDE8F21C0679D00FB35E4 /* main.swift */, 144 | E69A58CB21CB301700FB35E4 /* XPC Service */, 145 | E69A58CA21CB300C00FB35E4 /* Code Injection */, 146 | E69A58C921CB2FFB00FB35E4 /* Extensions and Utilities */, 147 | E6B1F2B021C1FD7E00FB35E4 /* AirPlayEnabler-Bridging-Header.h */, 148 | E65DDE9E21C06A8B00FB35E4 /* Launchd.plist */, 149 | E65DDE9D21C0684C00FB35E4 /* Info.plist */, 150 | ); 151 | path = AirPlayEnabler; 152 | sourceTree = ""; 153 | }; 154 | E667BC0621CDC41F00FB35E4 /* Patches */ = { 155 | isa = PBXGroup; 156 | children = ( 157 | E667BC0921CDC51400FB35E4 /* Patch+MacOS10_14.swift */, 158 | E69310742261544700FB35E4 /* Patch+MacOS10_14_4.swift */, 159 | ); 160 | path = Patches; 161 | sourceTree = ""; 162 | }; 163 | E688AE5D21C9774B00FB35E4 /* AirPlayEnablerInterface */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | E688AE5421C960FB00FB35E4 /* AirPlayEnablerInterface.swift */, 167 | E688AE7421C97F2400FB35E4 /* AirPlayEnablerInterfaceError.swift */, 168 | E6FAA06321CC269200FB35E4 /* PrivilegedHelperVersion.swift */, 169 | ); 170 | path = AirPlayEnablerInterface; 171 | sourceTree = ""; 172 | }; 173 | E69A58C921CB2FFB00FB35E4 /* Extensions and Utilities */ = { 174 | isa = PBXGroup; 175 | children = ( 176 | E688AE7721C9AE1100FB35E4 /* PrivilegedHelperInfo.swift */, 177 | E6D4063421D3390400FB35E4 /* ActivityTracing.swift */, 178 | E6B1F2BD21C5C33B00FB35E4 /* ActivityTracing.h */, 179 | E6B1F2BE21C5C33B00FB35E4 /* ActivityTracing.m */, 180 | ); 181 | path = "Extensions and Utilities"; 182 | sourceTree = ""; 183 | }; 184 | E69A58CA21CB300C00FB35E4 /* Code Injection */ = { 185 | isa = PBXGroup; 186 | children = ( 187 | E65DDEAF21C1F2A500FB35E4 /* CodeInjector.swift */, 188 | E667BBFC21CD73DE00FB35E4 /* Patch.swift */, 189 | E667BC0B21CDCB4A00FB35E4 /* Patch+Requirement.swift */, 190 | E667BC0421CDC41A00FB35E4 /* Patch+DynamicCreation.swift */, 191 | E667BC0621CDC41F00FB35E4 /* Patches */, 192 | E6D4062A21D1F9C700FB35E4 /* InjectedCode.swift */, 193 | E6D4062E21D2D61900FB35E4 /* InjectedCode+ExternalSymbolInfo.swift */, 194 | E6D4062C21D2D5FE00FB35E4 /* InjectedCode+Data.swift */, 195 | E667BBFE21CD745F00FB35E4 /* MemoryData.swift */, 196 | E667BC0221CD7E2200FB35E4 /* ExecutableInfo+AddressInTaskSpace.swift */, 197 | E6B1F2BB21C4A39900FB35E4 /* ExecutableInfo+ByteOrder.swift */, 198 | E6D4062821D0AFCD00FB35E4 /* Data+TaskVM.swift */, 199 | E6D4062721D015EB00FB35E4 /* Low-Level Functions */, 200 | ); 201 | path = "Code Injection"; 202 | sourceTree = ""; 203 | }; 204 | E69A58CB21CB301700FB35E4 /* XPC Service */ = { 205 | isa = PBXGroup; 206 | children = ( 207 | E688AE5221C8AD5500FB35E4 /* XPCService.swift */, 208 | E688AE5621C9637B00FB35E4 /* XPCServiceImplementation.swift */, 209 | E69A58C321CACFC500FB35E4 /* XPCServiceImplementation+IsPrivilegedHelperRunning.swift */, 210 | E6FAA06521CC28EA00FB35E4 /* XPCServiceImplementation+GetPrivilegedHelperVersion.swift */, 211 | E688AE7921C9B84A00FB35E4 /* XPCServiceImplementation+UninstallPrivilegedHelper.swift */, 212 | ); 213 | path = "XPC Service"; 214 | sourceTree = ""; 215 | }; 216 | E6D4062721D015EB00FB35E4 /* Low-Level Functions */ = { 217 | isa = PBXGroup; 218 | children = ( 219 | E6B1F2B321C1FD9A00FB35E4 /* ExecutableInfo.h */, 220 | E6B1F2B121C1FD7E00FB35E4 /* ExecutableInfo.m */, 221 | E67FBFD621D0105A00FB35E4 /* ImageInfo.h */, 222 | E67FBFD521D0105A00FB35E4 /* ImageInfo.m */, 223 | E67FBFD921D010F000FB35E4 /* Common.h */, 224 | E67FBFD821D010F000FB35E4 /* Common.m */, 225 | ); 226 | path = "Low-Level Functions"; 227 | sourceTree = ""; 228 | }; 229 | /* End PBXGroup section */ 230 | 231 | /* Begin PBXHeadersBuildPhase section */ 232 | E688AE5821C9774B00FB35E4 /* Headers */ = { 233 | isa = PBXHeadersBuildPhase; 234 | buildActionMask = 2147483647; 235 | files = ( 236 | ); 237 | runOnlyForDeploymentPostprocessing = 0; 238 | }; 239 | /* End PBXHeadersBuildPhase section */ 240 | 241 | /* Begin PBXNativeTarget section */ 242 | E65DDE8B21C0679D00FB35E4 /* AirPlayEnabler */ = { 243 | isa = PBXNativeTarget; 244 | buildConfigurationList = E65DDE9321C0679D00FB35E4 /* Build configuration list for PBXNativeTarget "AirPlayEnabler" */; 245 | buildPhases = ( 246 | E65DDE8821C0679D00FB35E4 /* Sources */, 247 | E65DDE8921C0679D00FB35E4 /* Frameworks */, 248 | E65DDE8A21C0679D00FB35E4 /* CopyFiles */, 249 | ); 250 | buildRules = ( 251 | ); 252 | dependencies = ( 253 | E688AE6721C977AC00FB35E4 /* PBXTargetDependency */, 254 | ); 255 | name = AirPlayEnabler; 256 | productName = AirPlayEnabler; 257 | productReference = E65DDE8C21C0679D00FB35E4 /* mo.darren.optimus.player.mac.airplay-enabler */; 258 | productType = "com.apple.product-type.tool"; 259 | }; 260 | E688AE5B21C9774B00FB35E4 /* AirPlayEnablerInterface */ = { 261 | isa = PBXNativeTarget; 262 | buildConfigurationList = E688AE6221C9774B00FB35E4 /* Build configuration list for PBXNativeTarget "AirPlayEnablerInterface" */; 263 | buildPhases = ( 264 | E688AE5821C9774B00FB35E4 /* Headers */, 265 | E688AE5921C9774B00FB35E4 /* Sources */, 266 | E688AE5A21C9774B00FB35E4 /* Frameworks */, 267 | ); 268 | buildRules = ( 269 | ); 270 | dependencies = ( 271 | ); 272 | name = AirPlayEnablerInterface; 273 | productName = AirPlayEnablerInterface; 274 | productReference = E688AE5C21C9774B00FB35E4 /* libAirPlayEnablerInterface.a */; 275 | productType = "com.apple.product-type.library.static"; 276 | }; 277 | /* End PBXNativeTarget section */ 278 | 279 | /* Begin PBXProject section */ 280 | E65DDE8421C0679D00FB35E4 /* Project object */ = { 281 | isa = PBXProject; 282 | attributes = { 283 | LastSwiftUpdateCheck = 1010; 284 | LastUpgradeCheck = 1220; 285 | ORGANIZATIONNAME = "Darren Mo"; 286 | TargetAttributes = { 287 | E65DDE8B21C0679D00FB35E4 = { 288 | CreatedOnToolsVersion = 10.1; 289 | LastSwiftMigration = 1020; 290 | }; 291 | E688AE5B21C9774B00FB35E4 = { 292 | CreatedOnToolsVersion = 10.1; 293 | LastSwiftMigration = 1020; 294 | }; 295 | }; 296 | }; 297 | buildConfigurationList = E65DDE8721C0679D00FB35E4 /* Build configuration list for PBXProject "AirPlayEnabler" */; 298 | compatibilityVersion = "Xcode 9.3"; 299 | developmentRegion = en; 300 | hasScannedForEncodings = 0; 301 | knownRegions = ( 302 | en, 303 | Base, 304 | ); 305 | mainGroup = E65DDE8321C0679D00FB35E4; 306 | productRefGroup = E65DDE8D21C0679D00FB35E4 /* Products */; 307 | projectDirPath = ""; 308 | projectRoot = ""; 309 | targets = ( 310 | E65DDE8B21C0679D00FB35E4 /* AirPlayEnabler */, 311 | E688AE5B21C9774B00FB35E4 /* AirPlayEnablerInterface */, 312 | ); 313 | }; 314 | /* End PBXProject section */ 315 | 316 | /* Begin PBXSourcesBuildPhase section */ 317 | E65DDE8821C0679D00FB35E4 /* Sources */ = { 318 | isa = PBXSourcesBuildPhase; 319 | buildActionMask = 2147483647; 320 | files = ( 321 | E6D4062F21D2D61900FB35E4 /* InjectedCode+ExternalSymbolInfo.swift in Sources */, 322 | E6B1F2B221C1FD7E00FB35E4 /* ExecutableInfo.m in Sources */, 323 | E667BC0A21CDC51400FB35E4 /* Patch+MacOS10_14.swift in Sources */, 324 | E6D4062B21D1F9C700FB35E4 /* InjectedCode.swift in Sources */, 325 | E69310752261544700FB35E4 /* Patch+MacOS10_14_4.swift in Sources */, 326 | E67FBFDA21D010F000FB35E4 /* Common.m in Sources */, 327 | E6D4063521D3390400FB35E4 /* ActivityTracing.swift in Sources */, 328 | E65DDEB021C1F2A500FB35E4 /* CodeInjector.swift in Sources */, 329 | E667BC0521CDC41A00FB35E4 /* Patch+DynamicCreation.swift in Sources */, 330 | E69A58C421CACFC600FB35E4 /* XPCServiceImplementation+IsPrivilegedHelperRunning.swift in Sources */, 331 | E65DDE9021C0679D00FB35E4 /* main.swift in Sources */, 332 | E688AE5721C9637B00FB35E4 /* XPCServiceImplementation.swift in Sources */, 333 | E67FBFD721D0105A00FB35E4 /* ImageInfo.m in Sources */, 334 | E6D4062D21D2D5FE00FB35E4 /* InjectedCode+Data.swift in Sources */, 335 | E688AE7821C9AE1100FB35E4 /* PrivilegedHelperInfo.swift in Sources */, 336 | E688AE7A21C9B84A00FB35E4 /* XPCServiceImplementation+UninstallPrivilegedHelper.swift in Sources */, 337 | E6D4062921D0AFCD00FB35E4 /* Data+TaskVM.swift in Sources */, 338 | E6FAA06621CC28EA00FB35E4 /* XPCServiceImplementation+GetPrivilegedHelperVersion.swift in Sources */, 339 | E667BC0321CD7E2200FB35E4 /* ExecutableInfo+AddressInTaskSpace.swift in Sources */, 340 | E667BBFF21CD745F00FB35E4 /* MemoryData.swift in Sources */, 341 | E6B1F2BC21C4A39900FB35E4 /* ExecutableInfo+ByteOrder.swift in Sources */, 342 | E667BC0C21CDCB4A00FB35E4 /* Patch+Requirement.swift in Sources */, 343 | E6B1F2BF21C5C33B00FB35E4 /* ActivityTracing.m in Sources */, 344 | E667BBFD21CD73DE00FB35E4 /* Patch.swift in Sources */, 345 | E688AE5321C8AD5500FB35E4 /* XPCService.swift in Sources */, 346 | ); 347 | runOnlyForDeploymentPostprocessing = 0; 348 | }; 349 | E688AE5921C9774B00FB35E4 /* Sources */ = { 350 | isa = PBXSourcesBuildPhase; 351 | buildActionMask = 2147483647; 352 | files = ( 353 | E6FAA06421CC269200FB35E4 /* PrivilegedHelperVersion.swift in Sources */, 354 | E688AE7521C97F2400FB35E4 /* AirPlayEnablerInterfaceError.swift in Sources */, 355 | E688AE6521C9775D00FB35E4 /* AirPlayEnablerInterface.swift in Sources */, 356 | ); 357 | runOnlyForDeploymentPostprocessing = 0; 358 | }; 359 | /* End PBXSourcesBuildPhase section */ 360 | 361 | /* Begin PBXTargetDependency section */ 362 | E688AE6721C977AC00FB35E4 /* PBXTargetDependency */ = { 363 | isa = PBXTargetDependency; 364 | target = E688AE5B21C9774B00FB35E4 /* AirPlayEnablerInterface */; 365 | targetProxy = E688AE6621C977AC00FB35E4 /* PBXContainerItemProxy */; 366 | }; 367 | /* End PBXTargetDependency section */ 368 | 369 | /* Begin XCBuildConfiguration section */ 370 | E65DDE9121C0679D00FB35E4 /* Debug */ = { 371 | isa = XCBuildConfiguration; 372 | buildSettings = { 373 | ALWAYS_SEARCH_USER_PATHS = NO; 374 | CLANG_ANALYZER_NONNULL = YES; 375 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 376 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 377 | CLANG_CXX_LIBRARY = "libc++"; 378 | CLANG_ENABLE_MODULES = YES; 379 | CLANG_ENABLE_OBJC_ARC = YES; 380 | CLANG_ENABLE_OBJC_WEAK = YES; 381 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 382 | CLANG_WARN_BOOL_CONVERSION = YES; 383 | CLANG_WARN_COMMA = YES; 384 | CLANG_WARN_CONSTANT_CONVERSION = YES; 385 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 386 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 387 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 388 | CLANG_WARN_EMPTY_BODY = YES; 389 | CLANG_WARN_ENUM_CONVERSION = YES; 390 | CLANG_WARN_INFINITE_RECURSION = YES; 391 | CLANG_WARN_INT_CONVERSION = YES; 392 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 393 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 394 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 395 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 396 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 397 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 398 | CLANG_WARN_STRICT_PROTOTYPES = YES; 399 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 400 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 401 | CLANG_WARN_UNREACHABLE_CODE = YES; 402 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 403 | CODE_SIGN_IDENTITY = "Mac Developer"; 404 | COPY_PHASE_STRIP = NO; 405 | CURRENT_PROJECT_VERSION = 3; 406 | DEBUG_INFORMATION_FORMAT = dwarf; 407 | ENABLE_STRICT_OBJC_MSGSEND = YES; 408 | ENABLE_TESTABILITY = YES; 409 | GCC_C_LANGUAGE_STANDARD = gnu11; 410 | GCC_DYNAMIC_NO_PIC = NO; 411 | GCC_NO_COMMON_BLOCKS = YES; 412 | GCC_OPTIMIZATION_LEVEL = 0; 413 | GCC_PREPROCESSOR_DEFINITIONS = ( 414 | "DEBUG=1", 415 | "$(inherited)", 416 | ); 417 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 418 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 419 | GCC_WARN_UNDECLARED_SELECTOR = YES; 420 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 421 | GCC_WARN_UNUSED_FUNCTION = YES; 422 | GCC_WARN_UNUSED_VARIABLE = YES; 423 | MACOSX_DEPLOYMENT_TARGET = 10.14; 424 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 425 | MTL_FAST_MATH = YES; 426 | ONLY_ACTIVE_ARCH = YES; 427 | SDKROOT = macosx; 428 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 429 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 430 | SWIFT_VERSION = 4.2; 431 | VERSIONING_SYSTEM = "apple-generic"; 432 | }; 433 | name = Debug; 434 | }; 435 | E65DDE9221C0679D00FB35E4 /* Release */ = { 436 | isa = XCBuildConfiguration; 437 | buildSettings = { 438 | ALWAYS_SEARCH_USER_PATHS = NO; 439 | CLANG_ANALYZER_NONNULL = YES; 440 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 441 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 442 | CLANG_CXX_LIBRARY = "libc++"; 443 | CLANG_ENABLE_MODULES = YES; 444 | CLANG_ENABLE_OBJC_ARC = YES; 445 | CLANG_ENABLE_OBJC_WEAK = YES; 446 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 447 | CLANG_WARN_BOOL_CONVERSION = YES; 448 | CLANG_WARN_COMMA = YES; 449 | CLANG_WARN_CONSTANT_CONVERSION = YES; 450 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 451 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 452 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 453 | CLANG_WARN_EMPTY_BODY = YES; 454 | CLANG_WARN_ENUM_CONVERSION = YES; 455 | CLANG_WARN_INFINITE_RECURSION = YES; 456 | CLANG_WARN_INT_CONVERSION = YES; 457 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 458 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 459 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 460 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 461 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 462 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 463 | CLANG_WARN_STRICT_PROTOTYPES = YES; 464 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 465 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 466 | CLANG_WARN_UNREACHABLE_CODE = YES; 467 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 468 | CODE_SIGN_IDENTITY = "Mac Developer"; 469 | COPY_PHASE_STRIP = NO; 470 | CURRENT_PROJECT_VERSION = 3; 471 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 472 | ENABLE_NS_ASSERTIONS = NO; 473 | ENABLE_STRICT_OBJC_MSGSEND = YES; 474 | GCC_C_LANGUAGE_STANDARD = gnu11; 475 | GCC_NO_COMMON_BLOCKS = YES; 476 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 477 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 478 | GCC_WARN_UNDECLARED_SELECTOR = YES; 479 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 480 | GCC_WARN_UNUSED_FUNCTION = YES; 481 | GCC_WARN_UNUSED_VARIABLE = YES; 482 | MACOSX_DEPLOYMENT_TARGET = 10.14; 483 | MTL_ENABLE_DEBUG_INFO = NO; 484 | MTL_FAST_MATH = YES; 485 | SDKROOT = macosx; 486 | SWIFT_COMPILATION_MODE = wholemodule; 487 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 488 | SWIFT_VERSION = 4.2; 489 | VERSIONING_SYSTEM = "apple-generic"; 490 | }; 491 | name = Release; 492 | }; 493 | E65DDE9421C0679D00FB35E4 /* Debug */ = { 494 | isa = XCBuildConfiguration; 495 | buildSettings = { 496 | CLANG_ENABLE_MODULES = YES; 497 | CODE_SIGN_IDENTITY = "Developer ID Application"; 498 | CODE_SIGN_STYLE = Manual; 499 | CREATE_INFOPLIST_SECTION_IN_BINARY = YES; 500 | DEVELOPMENT_TEAM = PVLQ49LAH3; 501 | ENABLE_HARDENED_RUNTIME = YES; 502 | INFOPLIST_FILE = AirPlayEnabler/Info.plist; 503 | LD_RUNPATH_SEARCH_PATHS = ( 504 | "$(inherited)", 505 | "@executable_path/../Frameworks", 506 | "@loader_path/../Frameworks", 507 | ); 508 | OTHER_LDFLAGS = ( 509 | "-sectcreate", 510 | __TEXT, 511 | __launchd_plist, 512 | "$(SRCROOT)/AirPlayEnabler/Launchd.plist", 513 | ); 514 | PRODUCT_BUNDLE_IDENTIFIER = "mo.darren.optimus.player.mac.airplay-enabler"; 515 | PRODUCT_NAME = "$(PRODUCT_BUNDLE_IDENTIFIER)"; 516 | PROVISIONING_PROFILE_SPECIFIER = ""; 517 | SKIP_INSTALL = YES; 518 | SWIFT_OBJC_BRIDGING_HEADER = "AirPlayEnabler/AirPlayEnabler-Bridging-Header.h"; 519 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 520 | SWIFT_VERSION = 4.2; 521 | }; 522 | name = Debug; 523 | }; 524 | E65DDE9521C0679D00FB35E4 /* Release */ = { 525 | isa = XCBuildConfiguration; 526 | buildSettings = { 527 | CLANG_ENABLE_MODULES = YES; 528 | CODE_SIGN_IDENTITY = "Developer ID Application"; 529 | CODE_SIGN_STYLE = Manual; 530 | CREATE_INFOPLIST_SECTION_IN_BINARY = YES; 531 | DEVELOPMENT_TEAM = PVLQ49LAH3; 532 | ENABLE_HARDENED_RUNTIME = YES; 533 | INFOPLIST_FILE = AirPlayEnabler/Info.plist; 534 | LD_RUNPATH_SEARCH_PATHS = ( 535 | "$(inherited)", 536 | "@executable_path/../Frameworks", 537 | "@loader_path/../Frameworks", 538 | ); 539 | OTHER_LDFLAGS = ( 540 | "-sectcreate", 541 | __TEXT, 542 | __launchd_plist, 543 | "$(SRCROOT)/AirPlayEnabler/Launchd.plist", 544 | ); 545 | PRODUCT_BUNDLE_IDENTIFIER = "mo.darren.optimus.player.mac.airplay-enabler"; 546 | PRODUCT_NAME = "$(PRODUCT_BUNDLE_IDENTIFIER)"; 547 | PROVISIONING_PROFILE_SPECIFIER = ""; 548 | SKIP_INSTALL = YES; 549 | SWIFT_OBJC_BRIDGING_HEADER = "AirPlayEnabler/AirPlayEnabler-Bridging-Header.h"; 550 | SWIFT_VERSION = 4.2; 551 | }; 552 | name = Release; 553 | }; 554 | E688AE6321C9774B00FB35E4 /* Debug */ = { 555 | isa = XCBuildConfiguration; 556 | buildSettings = { 557 | CODE_SIGN_STYLE = Automatic; 558 | DEVELOPMENT_TEAM = PVLQ49LAH3; 559 | EXECUTABLE_PREFIX = lib; 560 | PRODUCT_NAME = "$(TARGET_NAME)"; 561 | SKIP_INSTALL = YES; 562 | SWIFT_VERSION = 4.2; 563 | }; 564 | name = Debug; 565 | }; 566 | E688AE6421C9774B00FB35E4 /* Release */ = { 567 | isa = XCBuildConfiguration; 568 | buildSettings = { 569 | CODE_SIGN_STYLE = Automatic; 570 | DEVELOPMENT_TEAM = PVLQ49LAH3; 571 | EXECUTABLE_PREFIX = lib; 572 | PRODUCT_NAME = "$(TARGET_NAME)"; 573 | SKIP_INSTALL = YES; 574 | SWIFT_VERSION = 4.2; 575 | }; 576 | name = Release; 577 | }; 578 | /* End XCBuildConfiguration section */ 579 | 580 | /* Begin XCConfigurationList section */ 581 | E65DDE8721C0679D00FB35E4 /* Build configuration list for PBXProject "AirPlayEnabler" */ = { 582 | isa = XCConfigurationList; 583 | buildConfigurations = ( 584 | E65DDE9121C0679D00FB35E4 /* Debug */, 585 | E65DDE9221C0679D00FB35E4 /* Release */, 586 | ); 587 | defaultConfigurationIsVisible = 0; 588 | defaultConfigurationName = Release; 589 | }; 590 | E65DDE9321C0679D00FB35E4 /* Build configuration list for PBXNativeTarget "AirPlayEnabler" */ = { 591 | isa = XCConfigurationList; 592 | buildConfigurations = ( 593 | E65DDE9421C0679D00FB35E4 /* Debug */, 594 | E65DDE9521C0679D00FB35E4 /* Release */, 595 | ); 596 | defaultConfigurationIsVisible = 0; 597 | defaultConfigurationName = Release; 598 | }; 599 | E688AE6221C9774B00FB35E4 /* Build configuration list for PBXNativeTarget "AirPlayEnablerInterface" */ = { 600 | isa = XCConfigurationList; 601 | buildConfigurations = ( 602 | E688AE6321C9774B00FB35E4 /* Debug */, 603 | E688AE6421C9774B00FB35E4 /* Release */, 604 | ); 605 | defaultConfigurationIsVisible = 0; 606 | defaultConfigurationName = Release; 607 | }; 608 | /* End XCConfigurationList section */ 609 | }; 610 | rootObject = E65DDE8421C0679D00FB35E4 /* Project object */; 611 | } 612 | --------------------------------------------------------------------------------