I'm a security researcher and I sometimes use Swift to pull in classes from frameworks on macOS, when I am unable to easily access them. The below example shows how I would get and use the NSString
class, just for reference:
let FoundationPtr = dlopen("/System/Library/Frameworks/Foundation.framework/Foundation", RTLD_LAZY)
let NSStringPtr = dlsym(FoundationPtr, "OBJC_CLASS_$_NSString")
@objc protocol NSStringProtocol: NSObjectProtocol {
init(string: String)
}
let _NSString = unsafeBitCast(NSStringPtr, to: NSStringProtocol.Type.self)
let string = _NSString.init(string: "Hello, world!")
print(string)
This works nicely, but is a bit verbose. I tried to make a generic function that does all of this like so:
func makeClassFromFrameworkSymbol<T: NSObjectProtocol>(
frameworkName: String, className: String, castTo: T.Type = NSObjectProtocol.self
) -> T.Type? {
let FrameworkPtr = dlopen(
"/System/Library/Frameworks/\(frameworkName).framework/\(frameworkName)", RTLD_LAZY)
let ClassPtr = dlsym(FrameworkPtr, "OBJC_CLASS_$_\(className)")
return unsafeBitCast(ClassPtr, to: T.Type.self)
}
Unfortunately, the return type of that function, when used as before, is (any NSStringProtocol).Type
instead of any NSStringProtocol.Type
(notice the parentheses).
Trying to use the function like so:
let __NSString = makeClassFromFrameworkSymbol(
frameworkName: "Foundation", className: "NSString", castTo: NSStringProtocol.self)
let string2 = __NSString!.init(string: "Hello, world!")
results in compiler errors.
Am I doing something wrong with my generic function?