Skip to content

Instantly share code, notes, and snippets.

@BrianHenryIE
Created October 22, 2023 22:02
Show Gist options
  • Save BrianHenryIE/782993daa2b4c9be6b727f2636ae06c8 to your computer and use it in GitHub Desktop.
Save BrianHenryIE/782993daa2b4c9be6b727f2636ae06c8 to your computer and use it in GitHub Desktop.
Parse an executable for strings and add DistributedNotification listeners for each
//
// notifier
//
// Created by Josh Wisenbaker on 3/12/18.
// Copyright © 2018 Josh Wisenbaker. All rights reserved.
//
// @see https://gitlab.com/-/snippets/1704123
//
// @see https://medium.com/macoclock/finding-distributed-notifications-on-macos-catalina-b2a292aac5a1
//
// Modified by BrianHenryIE to parse executables for strings and add listeners for them.
import Foundation
// https://stackoverflow.com/questions/29514738/get-terminal-output-after-a-command-swift
extension String : LocalizedError {
public var errorDescription: String? { self }
}
// https://stackoverflow.com/questions/29514738/get-terminal-output-after-a-command-swift
extension Process {
func run(_ executableURL: URL, arguments: [String]? = nil) throws -> String {
self.executableURL = executableURL
self.arguments = arguments
let pipe = Pipe()
standardOutput = pipe
standardError = pipe
try run()
_ = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: true) { timer in
self.terminate()
}
// This never happens.
waitUntilExit()
let output = String(data: pipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8)
return output?.trimmingCharacters(in: .newlines) ?? ""
}
}
// https://stackoverflow.com/questions/27624331/unique-values-of-array-in-swift
extension Array where Element: Equatable {
var unique: [Element] {
var uniqueValues: [Element] = []
forEach { item in
guard !uniqueValues.contains(item) else { return }
uniqueValues.append(item)
}
return uniqueValues
}
}
// https://stackoverflow.com/questions/24181699/how-to-check-if-a-file-exists-in-the-documents-directory-in-swift
extension FileManager {
class func fileExists(filePath: String) -> Bool {
var isDirectory = ObjCBool(false)
return self.default.fileExists(atPath: filePath, isDirectory: &isDirectory)
}
}
// https://gitlab.com/-/snippets/1704123
class watcher {
init() {
let filePath = CommandLine.arguments[1]
if !FileManager.fileExists(filePath: filePath) {
print("File not found: \(filePath)")
exit(1)
}
let taskProcess = Process()
print("Getting strings for \(filePath)")
let result: String = try! taskProcess.run(
URL(filePath: "/usr/bin/strings"),
arguments: [
filePath
]
)
let potentialNotificationNames = result.split(separator: "\n").map { String($0) }.unique
potentialNotificationNames.forEach(
{
print("adding listener for \($0)")
DistributedNotificationCenter.default().addObserver(self,
selector: #selector(self.logit(note:)),
name: Notification.Name($0),
object: nil) }
)
}
@objc func logit(note: NSNotification) {
print(note)
}
}
let myWatcher = watcher()
dispatchMain()
@BrianHenryIE
Copy link
Author

Use:

$ swiftc notifier.swift
$ ./notifier /System/Library/CoreServices/backupd.bundle/Contents/Resources/backupd-helper
Getting strings for /System/Library/CoreServices/backupd.bundle/Contents/Resources/backupd-helper
adding listener for @fpmc
...
adding listener for B48@0:8@16@24Q32^@40
__CFNotification 0x600002748000 {name = com.apple.TimeMachine.UICleanupNeeded; object = com.apple.backupd; userInfo = {
    DestinationID = "511D3A0B-8810-4704-B45B-E2A2FFC26DAE";
}}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment