-
-
Notifications
You must be signed in to change notification settings - Fork 255
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Exclude files or code from obfuscation #31
Changes from all commits
19bd123
b3d74f5
ce185ee
15b11ec
b61ef7f
2497314
a9a8797
25ba5aa
ec9c5c7
c04bb0e
0a53168
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,5 @@ | ||
|
||
*.profraw | ||
.DS_Store | ||
Index/DataStore/* | ||
Build/Intermediates.noindex/* |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,9 @@ class AutomaticSwiftShield: Protector { | |
let projectToBuild: String | ||
let schemeToBuild: String | ||
let modulesToIgnore: Set<String> | ||
|
||
var publicProtocols: Set<String>! | ||
let excludePublic: Bool | ||
|
||
var isWorkspace: Bool { | ||
return projectToBuild.hasSuffix(".xcworkspace") | ||
} | ||
|
@@ -14,10 +16,12 @@ class AutomaticSwiftShield: Protector { | |
projectToBuild: String, | ||
schemeToBuild: String, | ||
modulesToIgnore: Set<String>, | ||
protectedClassNameSize: Int) { | ||
protectedClassNameSize: Int, | ||
excludePublic: Bool) { | ||
self.projectToBuild = projectToBuild | ||
self.schemeToBuild = schemeToBuild | ||
self.modulesToIgnore = modulesToIgnore | ||
self.excludePublic = excludePublic | ||
super.init(basePath: basePath, protectedClassNameSize: protectedClassNameSize) | ||
if self.schemeToBuild.isEmpty || self.projectToBuild.isEmpty { | ||
Logger.log(.helpText) | ||
|
@@ -33,7 +37,7 @@ class AutomaticSwiftShield: Protector { | |
let projectBuilder = XcodeProjectBuilder(projectToBuild: projectToBuild, schemeToBuild: schemeToBuild, modulesToIgnore: modulesToIgnore) | ||
let modules = projectBuilder.getModulesAndCompilerArguments() | ||
let obfuscationData = AutomaticObfuscationData(modules: modules) | ||
index(obfuscationData: obfuscationData) | ||
index(obfuscationData: obfuscationData, shouldRemoveSuffixTags: false) | ||
findReferencesInIndexed(obfuscationData: obfuscationData) | ||
if obfuscationData.referencesDict.isEmpty { | ||
Logger.log(.foundNothingError) | ||
|
@@ -44,7 +48,7 @@ class AutomaticSwiftShield: Protector { | |
return obfuscationData | ||
} | ||
|
||
func index(obfuscationData: AutomaticObfuscationData) { | ||
func index(obfuscationData: AutomaticObfuscationData, shouldRemoveSuffixTags: Bool) { | ||
let sourceKit = SourceKit() | ||
var fileDataArray: [(file: File, module: Module)] = [] | ||
for module in obfuscationData.modules { | ||
|
@@ -59,10 +63,14 @@ class AutomaticSwiftShield: Protector { | |
Logger.log(.indexing(file: file)) | ||
let resp = index(sourceKit: sourceKit, file: file, args: compilerArgs) | ||
let dict = SKApi.sourcekitd_response_get_value(resp) | ||
|
||
publicProtocols = Set<String>() | ||
|
||
sourceKit.recurseOver(childID: sourceKit.entitiesID, resp: dict) { [unowned self] dict in | ||
guard let data = self.getNameData(from: dict, | ||
obfuscationData: obfuscationData, | ||
sourceKit: sourceKit) else { | ||
sourceKit: sourceKit, | ||
shouldRemoveSuffixTags: shouldRemoveSuffixTags) else { | ||
return | ||
} | ||
let name = data.name | ||
|
@@ -88,6 +96,20 @@ class AutomaticSwiftShield: Protector { | |
} | ||
writeToFile(data: data, path: path, info: "Automatic mode for \(path)") | ||
} | ||
|
||
func removeSuffixTags() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do not understand what this is supposed to be doing, is it a leftover from something? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. leftover, I will remove it. |
||
let projectBuilder = XcodeProjectBuilder(projectToBuild: projectToBuild, schemeToBuild: schemeToBuild, modulesToIgnore: modulesToIgnore) | ||
let modules = projectBuilder.getModulesAndCompilerArguments() | ||
let obfuscationData = AutomaticObfuscationData(modules: modules) | ||
index(obfuscationData: obfuscationData, shouldRemoveSuffixTags: true) | ||
findReferencesInIndexed(obfuscationData: obfuscationData) | ||
if obfuscationData.referencesDict.isEmpty { | ||
Logger.log(.foundNothingError) | ||
exit(error: true) | ||
} | ||
obfuscateNSPrincipalClassPlists(obfuscationData: obfuscationData) | ||
overwriteFiles(obfuscationData: obfuscationData) | ||
} | ||
} | ||
|
||
extension AutomaticSwiftShield { | ||
|
@@ -100,22 +122,56 @@ extension AutomaticSwiftShield { | |
return resp | ||
} | ||
|
||
private func getNameData(from dict: sourcekitd_variant_t, obfuscationData: ObfuscationData, sourceKit: SourceKit) -> (name: String, usr: String, obfuscatedName: String)? { | ||
private func getNameData(from dict: sourcekitd_variant_t, | ||
obfuscationData: ObfuscationData, | ||
sourceKit: SourceKit, | ||
shouldRemoveSuffixTags: Bool) -> (name: String, usr: String, obfuscatedName: String)? { | ||
|
||
let kind = dict.getUUIDString(key: sourceKit.kindID) | ||
guard sourceKit.declarationType(for: kind) != nil else { | ||
return nil | ||
} | ||
guard let name = dict.getString(key: sourceKit.nameID)?.trueName, let usr = dict.getString(key: sourceKit.usrID) else { | ||
return nil | ||
} | ||
|
||
if excludePublic { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To avoid making There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok |
||
let attributesDict = SKApi.sourcekitd_variant_dictionary_get_value(dict, sourceKit.attributesID) | ||
let attributesData = dict.getAttributes(dict: attributesDict, subKey: sourceKit.attributeID) | ||
|
||
|
||
//Check if variant is public | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's avoid comments unless explaining an intent is needed - what is happening should be clear enough through the name of the properties we're dealing with. |
||
let isPublic = attributesData.filter { item in | ||
return item.contains("public") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would avoid dealing with strings directly. We can make an enum to handle visibility identifiers. I already did that for kinds, so we can follow the same pattern 🙂 |
||
}.count != 0 | ||
|
||
//Add to publicProtocols array | ||
if kind == "source.lang.swift.decl.protocol" && isPublic { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same thing here (not dealing with strings directly), SKAPI already has a method to return what an identifier is - I think we just need to add the protocol case. |
||
publicProtocols.insert(name) | ||
} | ||
|
||
//Don't Obfuscate public methods/properties.. | ||
if isPublic { | ||
return nil | ||
} | ||
|
||
//Handle public protocol's functions | ||
for protocolName in publicProtocols { | ||
if usr.contains(protocolName) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I understood this correctly, shouldn't this be simply There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, because the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see now. The problem is that using But I'm getting some bad vibes, is this deterministic? I'm having the impression that a public protocol's method would be wrongly obfuscated if the order of the files changed. If you look at |
||
return nil | ||
} | ||
} | ||
} | ||
guard let protected = obfuscationData.obfuscationDict[name] else { | ||
//if !shouldRemoveSuffixTags { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can remove these leftovers There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will remove it. |
||
let newName = String.random(length: self.protectedClassNameSize, excluding: obfuscationData.allObfuscatedNames) | ||
obfuscationData.obfuscationDict[name] = newName | ||
return (name, usr, newName) | ||
} | ||
|
||
return (name, usr, protected) | ||
} | ||
|
||
func findReferencesInIndexed(obfuscationData: AutomaticObfuscationData) { | ||
let SK = SourceKit() | ||
Logger.log(.searchingReferencesOfUsr) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,4 +25,18 @@ extension sourcekitd_variant_t { | |
func getDictionary(key: sourcekitd_uid_t) -> sourcekitd_variant_t { | ||
return SKApi.sourcekitd_variant_dictionary_get_value(self, key) | ||
} | ||
|
||
func getAttributes(dict: sourcekitd_variant_t, subKey: sourcekitd_uid_t) -> [String] { | ||
|
||
var data = [String]() | ||
|
||
let _ = SKApi.sourcekitd_variant_array_apply(dict) { (_, attributesDict) in | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this safe? Wouldn't it crash on none-array |
||
|
||
let accessControl = attributesDict.getUUIDString(key: subKey) | ||
data.append(accessControl) | ||
return true | ||
} | ||
|
||
return data | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,9 +27,10 @@ final class SourceKit { | |
"struct", | ||
"protocol": | ||
return .object | ||
// case "var.instance", | ||
// "var.class": | ||
// return .property | ||
case "var.instance", | ||
"var.static", | ||
"var.class": | ||
return .property | ||
case "function.free", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if you enable property, confirm no storyboard property in use |
||
"function.method.instance", | ||
"function.method.static", | ||
|
@@ -73,7 +74,9 @@ final class SourceKit { | |
lazy var lineID = SKApi.sourcekitd_uid_get_from_cstr("key.line")! | ||
lazy var colID = SKApi.sourcekitd_uid_get_from_cstr("key.column")! | ||
lazy var usrID = SKApi.sourcekitd_uid_get_from_cstr("key.usr")! | ||
|
||
lazy var attributesID = SKApi.sourcekitd_uid_get_from_cstr("key.attributes")! | ||
lazy var attributeID = SKApi.sourcekitd_uid_get_from_cstr("key.attribute")! | ||
|
||
func array(argv: [String]) -> sourcekitd_object_t { | ||
let objects = argv.map { SKApi.sourcekitd_request_string_create($0) } | ||
return SKApi.sourcekitd_request_array_create(objects, objects.count)! | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,7 +37,9 @@ if automatic { | |
let schemeToBuild = UserDefaults.standard.string(forKey: "automatic-project-scheme") ?? "" | ||
let projectToBuild = UserDefaults.standard.string(forKey: "automatic-project-file") ?? "" | ||
let modulesToIgnore = UserDefaults.standard.string(forKey: "ignore-modules")?.components(separatedBy: ",") ?? [] | ||
protector = AutomaticSwiftShield(basePath: basePath, projectToBuild: projectToBuild, schemeToBuild: schemeToBuild, modulesToIgnore: Set(modulesToIgnore), protectedClassNameSize: protectedClassNameSize) | ||
let excludePublic = CommandLine.arguments.contains("-exclude-public") | ||
|
||
protector = AutomaticSwiftShield(basePath: basePath, projectToBuild: projectToBuild, schemeToBuild: schemeToBuild, modulesToIgnore: Set(modulesToIgnore), protectedClassNameSize: protectedClassNameSize, excludePublic: excludePublic) | ||
} else { | ||
let tag = UserDefaults.standard.string(forKey: "tag") ?? "__s" | ||
protector = ManualSwiftShield(basePath: basePath, tag: tag, protectedClassNameSize: protectedClassNameSize) | ||
|
@@ -53,4 +55,9 @@ protector.protectStoryboards(data: obfuscationData) | |
protector.writeToFile(data: obfuscationData) | ||
protector.markProjectsAsProtected() | ||
Logger.log(.finished) | ||
|
||
if automatic && CommandLine.arguments.contains("-clear-suffix-tags") { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that's also a leftover right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. leftover, I will remove it. |
||
(protector as! AutomaticSwiftShield).removeSuffixTags() | ||
} | ||
|
||
exit() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not use force unwrap - If storing the protocols here are needed, we can pre-init it for safety reasons 🙂
var publicProtocols: Set<String> = []
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok