Skip to content
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

Add obfuscation on Enum type and Enum elements #80

Merged
merged 3 commits into from
Jan 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ If one or more modules/extensions of your app fail to satify these conditions, y
2. No Objective-C classes that call Swift methods (Swift classes that call Objective-C methods are fine, except when interfacing is involved)
4. Latest Swift version and Xcode command line tools (works on all versions, but might have different results due to different SourceKit versions)
5. Make sure your project doesn't contain one of [SourceKit's bugs](SOURCEKITISSUES.md). Although the bugs won't prevent the project from being obfuscated, some of them might require some manual fixing afterwards.
6. Enum and enum elements will be obfuscated, except the enum name suffixed with `CodingKeys`. Make sure the name your the CodingKeys enum ending with `CodingKeys`.

(App Extensions that use `NSExtensionPrincipalClass` or variants in their `Info.plist` (like Rich Notifications/Watch apps) will have such references obfuscated as well, but will assume that you haven't changed them from their default `$(PRODUCT_MODULE_NAME).ClassName` value. If you modified these plists to point to classes in different modules, you'll have to manually change them after running this tool.)

Expand Down
18 changes: 18 additions & 0 deletions SwiftShieldExample/SwiftShieldExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

/* Begin PBXBuildFile section */
690E9FDA54E33AE150456400 /* Pods_SwiftShieldExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 906E79CBAAED7E65DB3DE1FF /* Pods_SwiftShieldExample.framework */; };
84F0B22C23C21BB4005CEE05 /* SwiftShieldSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 846A66E623AFA38D005801B8 /* SwiftShieldSDK.framework */; };
84F0B22D23C21BB4005CEE05 /* SwiftShieldSDK.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 846A66E623AFA38D005801B8 /* SwiftShieldSDK.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
FD5360EF212DFC21004FB44F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5360EE212DFC21004FB44F /* AppDelegate.swift */; };
FD5360F1212DFC21004FB44F /* MyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5360F0212DFC21004FB44F /* MyViewController.swift */; };
FD5360F4212DFC21004FB44F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FD5360F2212DFC21004FB44F /* Main.storyboard */; };
Expand Down Expand Up @@ -39,6 +41,20 @@
};
/* End PBXContainerItemProxy section */

/* Begin PBXCopyFilesBuildPhase section */
84F0B22E23C21BB5005CEE05 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
84F0B22D23C21BB4005CEE05 /* SwiftShieldSDK.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
846A66E023AFA38C005801B8 /* SwiftShieldSDK.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SwiftShieldSDK.xcodeproj; path = SwiftShieldSDK/SwiftShieldSDK.xcodeproj; sourceTree = "<group>"; };
887E68FDACDAF78F3E840DBC /* Pods-SwiftShieldExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftShieldExample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftShieldExample/Pods-SwiftShieldExample.debug.xcconfig"; sourceTree = "<group>"; };
Expand All @@ -58,6 +74,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
84F0B22C23C21BB4005CEE05 /* SwiftShieldSDK.framework in Frameworks */,
690E9FDA54E33AE150456400 /* Pods_SwiftShieldExample.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -135,6 +152,7 @@
FD5360E8212DFC21004FB44F /* Frameworks */,
FD5360E9212DFC21004FB44F /* Resources */,
9F318FF03689B66C34DE349D /* [CP] Embed Pods Frameworks */,
84F0B22E23C21BB5005CEE05 /* Embed Frameworks */,
);
buildRules = (
);
Expand Down
9 changes: 9 additions & 0 deletions SwiftShieldExample/SwiftShieldExample/MyViewController.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import UIKit
import Cartography
import Unbox
import SwiftShieldSDK

final class MyView: UILabel {}

Expand All @@ -27,6 +28,7 @@ class MyViewController: UIViewController {
// myProp = myLet * 10
// MyViewController.myStaticVar = MyViewController.myClassVar + MyViewController.myStaticLet * 5
render()
sdkTest()
}

func render() {
Expand All @@ -43,4 +45,11 @@ class MyViewController: UIViewController {
let text: String = try! box.unbox(key: "text")
view.text = text
}

func sdkTest() {
let serializer = ShieldSerializer()
serializer.jsonContactsList()
let json = "[ { \"firstName\" : \"Bruce\", \"lastName\" : \"Lee\" }, { \"firstName\" : \"Jackie\", \"lastName\" : \"Chan\" } ]"
serializer.parseContactsList(json: json)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
846A66EA23AFA3E9005801B8 /* Person.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846A66E923AFA3E9005801B8 /* Person.swift */; };
846A66EC23AFA49F005801B8 /* ContactsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846A66EB23AFA49F005801B8 /* ContactsList.swift */; };
8492DB3023B100E10015D585 /* NameList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8492DB2F23B100E10015D585 /* NameList.swift */; };
84D94A2723B798BE005FC134 /* NameEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D94A2623B798BE005FC134 /* NameEnum.swift */; };
84F0B22A23C2161A005CEE05 /* ShieldSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F0B22923C2161A005CEE05 /* ShieldSerializer.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand All @@ -35,6 +37,8 @@
846A66E923AFA3E9005801B8 /* Person.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Person.swift; sourceTree = "<group>"; };
846A66EB23AFA49F005801B8 /* ContactsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsList.swift; sourceTree = "<group>"; };
8492DB2F23B100E10015D585 /* NameList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NameList.swift; sourceTree = "<group>"; };
84D94A2623B798BE005FC134 /* NameEnum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NameEnum.swift; sourceTree = "<group>"; };
84F0B22923C2161A005CEE05 /* ShieldSerializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShieldSerializer.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -79,9 +83,11 @@
children = (
846A66C923AFA37C005801B8 /* SwiftShieldSDK.h */,
846A66CA23AFA37C005801B8 /* Info.plist */,
84D94A2623B798BE005FC134 /* NameEnum.swift */,
846A66E923AFA3E9005801B8 /* Person.swift */,
846A66EB23AFA49F005801B8 /* ContactsList.swift */,
8492DB2F23B100E10015D585 /* NameList.swift */,
84F0B22923C2161A005CEE05 /* ShieldSerializer.swift */,
);
path = SwiftShieldSDK;
sourceTree = "<group>";
Expand Down Expand Up @@ -207,6 +213,8 @@
846A66EC23AFA49F005801B8 /* ContactsList.swift in Sources */,
846A66EA23AFA3E9005801B8 /* Person.swift in Sources */,
8492DB3023B100E10015D585 /* NameList.swift in Sources */,
84D94A2723B798BE005FC134 /* NameEnum.swift in Sources */,
84F0B22A23C2161A005CEE05 /* ShieldSerializer.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -373,6 +381,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.rockbruno.SwiftShieldSDK;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SUPPORTS_MACCATALYST = NO;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
Expand Down Expand Up @@ -401,6 +410,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.rockbruno.SwiftShieldSDK;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SUPPORTS_MACCATALYST = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,33 @@
import Foundation


public class ContactsList {
public class ContactsList: Codable {
var contacts = Array<Person>()

private enum CodingKeys: String, CodingKey {
case contacts
}

required public init(from decoder:Decoder) throws {
var container = try decoder.unkeyedContainer()
var contacts = [Person]()
if let count = container.count {
contacts.reserveCapacity(count)
}

while !container.isAtEnd {
let person = try container.decode(Person.self)
contacts.append(person)
}

self.contacts = contacts
}

public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(contacts)
}

public init() {
var person = Person("Bruce", "Lee")
contacts.append(person)
Expand Down
16 changes: 16 additions & 0 deletions SwiftShieldExample/SwiftShieldSDK/SwiftShieldSDK/NameEnum.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// NameEnum.swift
// SwiftShieldSDK
//
// Created by Weidian on 28/12/19.
// Copyright © 2019 rockbruno. All rights reserved.
//

import Foundation

enum NameEnum: Int {
case
FIRST_NAME = 0,
MIDDLE_NAME,
LAST_NAME
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ open class NameList {
names.append(person)
}

public func printNames() -> String {
open func printNames() -> String {
return privatePrintNames()
}

Expand Down
18 changes: 17 additions & 1 deletion SwiftShieldExample/SwiftShieldSDK/SwiftShieldSDK/Person.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@

import Foundation

class Person {
class Person: Codable {
var firstName: String
var lastName: String

private enum _personCodingKeys: String, CodingKey {
case firstName
case lastName
}

init(_ firstName: String, _ lastName: String) {
self.firstName = firstName
self.lastName = lastName
Expand All @@ -20,5 +25,16 @@ class Person {
func fullName() -> String {
return "\(firstName) \(lastName)"
}

func getName(part: NameEnum) -> String? {
switch part {
case NameEnum.FIRST_NAME:
return firstName
case NameEnum.LAST_NAME:
return lastName
default:
return nil
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// Serializer.swift
// SwiftShieldSDK
//
// Created by Weidian on 5/1/20.
// Copyright © 2020 rockbruno. All rights reserved.
//

import Foundation

open class ShieldSerializer {

public init() {}

open func jsonContactsList() -> String? {
let list = ContactsList()
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let data = try! encoder.encode(list)
let jsonList = String(data: data, encoding: .utf8)
print(jsonList ?? "encoding error")
return jsonList
}

open func parseContactsList(json: String) -> ContactsList? {
let data = json.data(using: .utf8)!
let list = try! JSONDecoder().decode(ContactsList.self, from: data)
return list
}
}
35 changes: 31 additions & 4 deletions swiftshield-Sources/AutomaticSwiftShield.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ class AutomaticSwiftShield: Protector {
}
let name = data.name
let usr = data.usr
let kind = data.kind

if let type = self.sourceKit.referenceType(kind: kind), type == .enum && name.hasSuffix("CodingKeys") {
obfuscationData.excludedEnums.insert(self.usrWithoutSuffix(usr))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything looks good now, but I'm just wondering if we need to do self.usrWithoutSuffix(usr) here. The enum usr is already the stripped one, isn't it?

return
}

obfuscationData.usrDict.insert(usr)
if dict.getString(.receiverId) == nil {
obfuscationData.usrRelationDict[usr] = variant
Expand Down Expand Up @@ -130,7 +137,8 @@ extension AutomaticSwiftShield {
private func getNameData(from dict: SourceKitdResponse.Dictionary,
obfuscationData: ObfuscationData) -> (name: String,
usr: String,
obfuscatedName: String)? {
obfuscatedName: String,
kind: String)? {
let kind = dict.getUID(.kindId).asString
guard sourceKit.declarationType(for: kind) != nil else {
return nil
Expand All @@ -142,9 +150,18 @@ extension AutomaticSwiftShield {
guard let protected = obfuscationData.obfuscationDict[name] else {
let newName = String.random(length: self.protectedClassNameSize, excluding: obfuscationData.allObfuscatedNames)
obfuscationData.obfuscationDict[name] = newName
return (name, usr, newName)
return (name, usr, newName, kind)
}
return (name, usr, protected, kind)
}

private func usrWithoutSuffix(_ usr: String) -> String {
let lastIndex = usr.lastIndex(of: "_")
if let index = lastIndex {
let usrPrefix = usr[..<index]
return String(usrPrefix)
}
return (name, usr, protected)
return usr
}

func findReferencesInIndexed(obfuscationData: AutomaticObfuscationData) {
Expand All @@ -164,6 +181,15 @@ extension AutomaticSwiftShield {
guard obfuscationData.usrDict.contains(usr) else {
return
}


if type == .enumelement {
let usrPrefix = self.usrWithoutSuffix(usr)
if obfuscationData.excludedEnums.contains(usrPrefix) {
return
}
}

//Operators only get indexed as such if they are declared in a global scope
//Unfortunately, most people use public static func
//So we avoid obfuscating methods with small names to prevent obfuscating operators.
Expand All @@ -190,12 +216,13 @@ extension AutomaticSwiftShield {
kind: String,
variant: SourceKitdResponse.Variant,
obfuscationData: AutomaticObfuscationData) -> Bool {
guard type == .method || type == .property else {
guard type == .method || type == .property || type == .enumelement else {
return false
}
guard let usr = variant.getDictionary().getString(.usrId) else {
return false
}

if let relDict = obfuscationData.usrRelationDict[usr], relDict.val.data != variant.val.data {
return isReferencingInternal(type: type,
kind: kind,
Expand Down
1 change: 1 addition & 0 deletions swiftshield-Sources/ObfuscationData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ final class AutomaticObfuscationData: ObfuscationData {
var referencesDict: [File: [ReferenceData]] = [:]
var usrRelationDict: [String: SourceKitdResponse.Variant] = [:]
var indexedFiles: [(File, SourceKitdResponse)] = []
var excludedEnums: Set<String> = []

var moduleNames: Set<String> {
return Set(modules.compactMap { $0.name })
Expand Down
4 changes: 4 additions & 0 deletions swiftshield-Sources/SourceKit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ final class SourceKit {
"function.method.static",
"function.method.class":
return .method
case "enum":
return .enum
case "enumelement":
return .enumelement
default:
return nil
}
Expand Down
2 changes: 2 additions & 0 deletions swiftshield-Sources/SourceKitDeclarationType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@ extension SourceKit {
case `protocol`
case property
case method
case `enum`
case enumelement
}
}