├── 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 |
--------------------------------------------------------------------------------