Created
December 8, 2023 12:31
-
-
Save ShikiSuen/6a27466ab18e9a8c9b3b4b325286f6e5 to your computer and use it in GitHub Desktop.
"identifierForVendor" for macOS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// (c) 2023 and onwards The vChewing Project (MIT-NTL License). | |
// ==================== | |
// This code is released under the MIT license (SPDX-License-Identifier: MIT) | |
// ... with NTL restriction stating that: | |
// No trademark license is granted to use the trade names, trademarks, service | |
// marks, or product names of Contributor, except as required to fulfill notice | |
// requirements defined in MIT License. | |
/// A Swift script to check whether a non-system process is abusing the SecureEventInput. | |
import IOKit | |
import Foundation | |
// MARK: - macOS Support | |
#if canImport(AppKit) | |
import IOKit | |
// macOS 没有 UIDevice,咱们弄个冒牌的。 | |
struct UIDevice { | |
static let current = UIDevice() | |
var identifierForVendor: UUID? { | |
guard let rawData = copy_mac_address() as? Data else { return nil } | |
var rawStr = rawData.hexadecimalString | |
guard !rawStr.isEmpty else { return nil} | |
while rawStr.count < 32 { | |
rawStr = rawStr + rawStr | |
} | |
var slot1 = "" | |
var slot2 = "" | |
var slot3 = "" | |
var slot4 = "" | |
var slot5 = "" | |
while slot1.count < 8, let firstChar = rawStr.first { | |
slot1.append(firstChar.description) | |
rawStr.removeFirst(1) | |
} | |
while slot2.count < 4, let firstChar = rawStr.first { | |
slot2.append(firstChar.description) | |
rawStr.removeFirst(1) | |
} | |
while slot3.count < 4, let firstChar = rawStr.first { | |
slot3.append(firstChar.description) | |
rawStr.removeFirst(1) | |
} | |
while slot4.count < 4, let firstChar = rawStr.first { | |
slot4.append(firstChar.description) | |
rawStr.removeFirst(1) | |
} | |
while slot5.count < 12, let firstChar = rawStr.first { | |
slot5.append(firstChar.description) | |
rawStr.removeFirst(1) | |
} | |
return UUID.init(uuidString: "\(slot1)-\(slot2)-\(slot3)-\(slot4)-\(slot5)") | |
} | |
} | |
// Returns an object with a +1 retain count; the caller needs to release. | |
// ref: https://developer.apple.com/documentation/appstorereceipts/validating_receipts_on_the_device#//apple_ref/doc/uid/TP40010573-CH1-SW14 | |
private func io_service(named name: String, wantBuiltIn: Bool) -> io_service_t? { | |
let default_port: UInt32 = kIOMainPortDefault | |
var iterator = io_iterator_t() | |
defer { | |
if iterator != IO_OBJECT_NULL { | |
IOObjectRelease(iterator) | |
} | |
} | |
guard let matchingDict = IOBSDNameMatching(default_port, 0, name), | |
IOServiceGetMatchingServices(default_port, | |
matchingDict as CFDictionary, | |
&iterator) == KERN_SUCCESS, | |
iterator != IO_OBJECT_NULL | |
else { | |
return nil | |
} | |
var candidate = IOIteratorNext(iterator) | |
while candidate != IO_OBJECT_NULL { | |
if let cftype = IORegistryEntryCreateCFProperty(candidate, | |
"IOBuiltin" as CFString, | |
kCFAllocatorDefault, | |
0) { | |
let isBuiltIn = cftype.takeRetainedValue() as! CFBoolean | |
if wantBuiltIn == CFBooleanGetValue(isBuiltIn) { | |
return candidate | |
} | |
} | |
IOObjectRelease(candidate) | |
candidate = IOIteratorNext(iterator) | |
} | |
return nil | |
} | |
// ref: https://developer.apple.com/documentation/appstorereceipts/validating_receipts_on_the_device#//apple_ref/doc/uid/TP40010573-CH1-SW14 | |
private func copy_mac_address() -> CFData? { | |
// Prefer built-in network interfaces. | |
// For example, an external Ethernet adaptor can displace | |
// the built-in Wi-Fi as en0. | |
guard let service = io_service(named: "en0", wantBuiltIn: true) | |
?? io_service(named: "en1", wantBuiltIn: true) | |
?? io_service(named: "en0", wantBuiltIn: false) | |
else { return nil } | |
defer { IOObjectRelease(service) } | |
if let cftype = IORegistryEntrySearchCFProperty( | |
service, | |
kIOServicePlane, | |
"IOMACAddress" as CFString, | |
kCFAllocatorDefault, | |
IOOptionBits(kIORegistryIterateRecursively | kIORegistryIterateParents)) { | |
return (cftype as! CFData) | |
} | |
return nil | |
} | |
// ref: https://stackoverflow.com/a/7520655/4162914 | |
private extension Data { | |
var hexadecimalString: String { | |
let charA: UInt8 = 0x61 | |
let char0: UInt8 = 0x30 | |
func byteToChar(_ b: UInt8) -> Character { | |
Character(UnicodeScalar(b > 9 ? charA + b - 10 : char0 + b)) | |
} | |
let hexChars = flatMap {[ | |
byteToChar(($0 >> 4) & 0xF), | |
byteToChar($0 & 0xF) | |
]} | |
return String(hexChars) | |
} | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment