Some of these definitions do not fit, that's why I write them
launchd service running in the background
Thanks for reading and your help. 😌
Post
Replies
Boosts
Views
Activity
For Mac versions that do not have the kext endpoint security framework, that is, catalina and later, the system extension is loaded, while for the lower versions, kext is loaded. The program I am trying to make works as follows.
Don't pay too much attention to the arrows, the program will generally work like this.
When we open an application, it connects to the service and monitors and controls the transactions.
kext and system extension do the same thing
but kext uses kauth from old sdk. But the reason here is not related to kext
I have already made NSXPCConnection as you wrote.
Below I will write the code of the places causing the problem.
XPCConnection.swift
func connectToDaemon(bundle: Bundle, delegate: ClientXPCProtocol, handler: @escaping (Bool) -> Void) {
guard connection == nil else {
Logger(.Info, "Client already connected.")
handler(true)
return
}
guard getMachServiceName(from: bundle) == ClientBundle else {
handler(false)
return
}
let newConnection = NSXPCConnection(machServiceName: DaemonBundle)
newConnection.exportedObject = delegate
newConnection.exportedInterface = NSXPCInterface(with: ClientXPCProtocol.self)
newConnection.remoteObjectInterface = NSXPCInterface(with: DaemonXPCProtocol.self)
newConnection.invalidationHandler = {
self.connection = nil
Logger(.Info, "Daemon disconnected.")
handler(false)
}
newConnection.interruptionHandler = {
self.connection = nil
Logger(.Error, "Daemon interrupted.")
handler(false)
}
connection = newConnection
newConnection.resume()
let proxy = newConnection.remoteObjectProxyWithErrorHandler { error in
Logger(.Error, "Failed to connect with error [\(error)]")
self.connection?.invalidate()
self.connection = nil
handler(false)
} as? DaemonXPCProtocol
proxy!.connectResponse(handler)
handler(true)
}
XPCServer.swift
class XPCServer: NSObject {
static let shared = XPCServer()
var fusionlog = FusionLog()
var listener: NSXPCListener?
var connection: NSXPCConnection?
private func getMachServiceName(from bundle: Bundle) -> String {
let clientKeys = bundle.object(forInfoDictionaryKey: ClientName) as? [String: Any]
let machServiceName = clientKeys?[MachServiceKey] as? String
return machServiceName ?? ""
}
func connectToSext(bundle: Bundle, delegate: ManagerXPCProtocol, handler: @escaping (Bool) -> Void) {
guard connection == nil else {
Logger(.Info, "Manager already connected.")
handler(true)
return
}
guard getMachServiceName(from: bundle) == ClientBundle else {
handler(false)
return
}
let newConnection = NSXPCConnection(machServiceName: SextBundle)
newConnection.exportedObject = delegate
newConnection.exportedInterface = NSXPCInterface(with: ManagerXPCProtocol.self)
newConnection.remoteObjectInterface = NSXPCInterface(with: SextXPCProtocol.self)
newConnection.invalidationHandler = {
self.connection = nil
Logger(.Info, "System Extensions disconnected.")
handler(false)
}
newConnection.interruptionHandler = {
self.connection = nil
Logger(.Error, "System Extensions interrupted.")
handler(false)
}
connection = newConnection
newConnection.resume()
let proxy = newConnection.remoteObjectProxyWithErrorHandler { error in
Logger(.Error, "Failed to connect with error [\(error)]")
self.connection?.invalidate()
self.connection = nil
handler(false)
} as? SextXPCProtocol
proxy?.connectResponse(handler)
handler(true)
}
}
FusionCommon.swift
func getSignInfoFromPath(_ path: String) -> [String] {
let fileUrl = URL(fileURLWithPath: path)
var secCode: SecStaticCode?
var status = SecStaticCodeCreateWithPath(fileUrl as CFURL, SecCSFlags(rawValue: 0), &secCode)
if status != errSecSuccess || secCode == nil {
Logger(.Warning, "Failed to create static signed code for [\(path)] with error [\(status)].")
return []
}
var secDict: CFDictionary?
status = SecCodeCopySigningInformation(secCode!, SecCSFlags(rawValue: kSecCSSigningInformation), &secDict)
if status != errSecSuccess || secDict == nil {
Logger(.Warning, "Failed to copy signed info for [\(path)] with error [\(status)].")
return []
}
let signedDict = secDict! as NSDictionary
guard let certChain = signedDict[kSecCodeInfoCertificates as NSString] as? NSArray else {
return []
}
var signInfo = [String]()
for cert in certChain {
var name: CFString?
status = SecCertificateCopyCommonName(cert as! SecCertificate, &name)
if status != errSecSuccess || name == nil {
continue
}
signInfo.append((name! as String))
}
return signInfo
}
Hello Quinn,
I apologize for the delay in my response. I'm a high school student currently in exam week. Thank you for your feedback.
To clarify, I'm actually working on a delegate but it looks like there might be some confusion in the terminology. Let me explain:
I created a normal mac app project in xcode and this application is launched with launchd
The xpc service is not as you say, I created a new app with a new target and made it run completely in the background. This background becomes my service and it loads the endpoint security system extension and kext. I created the endpoint security plugin using the Endpoint Security framework
According to your last question, launchd starts the program's service and loads the kext and system extension in the service.
Thank you for your help and reading this message.
Kind regards,
Bugra