Slide 1

Slide 1 text

Swift compiler as a library: 
 obfuscator case Krzysztof Siejkowski

Slide 2

Slide 2 text

In software development, obfuscation is the deliberate act of creating source or machine code that is difficult for humans to understand — Wikipedia

Slide 3

Slide 3 text

App Store YourApp binary file Your source code

Slide 4

Slide 4 text

App Store YourApp binary file YourApp encrypted (FairPlay) Jailbroken device YourApp binary file Your source code

Slide 5

Slide 5 text

App Store YourApp binary file YourApp encrypted (FairPlay) YourApp decrypted (in memory) Memory dump tool YourApp binary file Jailbroken device YourApp binary file Your source code

Slide 6

Slide 6 text

App Store YourApp binary file YourApp encrypted (FairPlay) YourApp decrypted (in memory) Memory dump tool YourApp binary file Your source code Disassembler (Hopper) Assembly/pseudo-code Jailbroken device

Slide 7

Slide 7 text

App Store YourApp binary file YourApp encrypted (FairPlay) YourApp decrypted (in memory) Memory dump tool YourApp binary file Your source code Disassembler (Hopper) Assembly/pseudo-code Jailbroken device

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

class MyViewController: UIViewController {} class MyView: UIView {} class MyModel: NSManagedObject {} class MyRuntimeUsingObject: NSObject {} class SomeClass { @objc func someFunc() {} }

Slide 13

Slide 13 text

Obfuscation is more than symbol renaming 
 Code Obfuscation Techniques for Software Protection
 —PhD thesis by Jan Cappaert
 


Slide 14

Slide 14 text

How to obfuscate? • after compilation • during compilation • before compilation

Slide 15

Slide 15 text

After compilation: binary to binary iXGuard (https://www.guardsquare.com/en/ixguard)

Slide 16

Slide 16 text

During compilation: source to binary Obfuscator-LLVM (https://github.com/obfuscator-llvm/obfuscator)

Slide 17

Slide 17 text

Before compilation: source to source WE!!!

Slide 18

Slide 18 text

Goal: obfuscate Swift code 
 by renaming

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

Does it work?

Slide 22

Slide 22 text

Does it work? YES

Slide 23

Slide 23 text

Not universal tool… • no DSYM support • no multiple targets • no mixed Swift/Obj-C • not all Swift constructs supported

Slide 24

Slide 24 text

…but still powerful • Storyboards/XIBs renaming • various Swift expressions supported • excluding configuration • very easy to integrate

Slide 25

Slide 25 text

$ bin/sirius -help USAGE: sirius -projectrootpath [PROJECTROOTPATH] -obfuscatedproject [OBFUSCATEDPROJECTPATH]

Slide 26

Slide 26 text

Xcode project Zobfuskowany Xcode project Command line interface (standalone or as Xcode build step) Original Xcode project Obfuscated Xcode project (copy or inplace)

Slide 27

Slide 27 text

Original Xcode project Xcode project parsing Symbols identification Generation of new names Obfuscated Xcode project (copy or inplace) Renaming in the source files

Slide 28

Slide 28 text

Original Xcode project Xcode project parsing

Slide 29

Slide 29 text

Original Xcode project Xcode project parsing Symbols identification

Slide 30

Slide 30 text

Original Xcode project Xcode project parsing Symbols identification Generation of new names

Slide 31

Slide 31 text

Original Xcode project Xcode project parsing Symbols identification Generation of new names Obfuscated Xcode project Renaming in the source files

Slide 32

Slide 32 text

Obfuscation verification Original Xcode project Xcode project parsing Symbols identification Generation of new names Obfuscated Xcode project Renaming in the source files Main command line interface

Slide 33

Slide 33 text

Obfuscation verification Original Xcode project Xcode project parsing Obfuscated Xcode project Main command line interface Swift compiler Symbols identification Generation of new names Renaming in the source files

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

1. create new folder in swift/tools
 2. add add_swift_tool_subdirectory function 
 to swift/tools/CMakeLists.txt
 3. create new .cpp file with main function 
 4. create new CMakeLists.txt for your tool
 5. add add_swift_host_tool function 
 to swift/tools//CMakeLists.txt 
 and define the source files, executable name and dependencies How to add new command line tool?

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

No content

Slide 50

Slide 50 text

1. create new folders in swift/include/swift and swift/lib
 2. add your .h interfaces 
 to swift/include/swift/
 3. add your .cpp implementations to swift/lib/
 4. create CMakeLists.txt for your library 
 at swift/lib//CMakeLists.txt 
 with add_swift_library function 
 that defines the source files, library name and dependencies
 5. add add_subdirectory function to swift/lib/CMakeLists.txt 
 How to add new library?

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

1. create new folder in swift/unittests
 2. add your .cpp test source code 
 to swift/unittests/
 3. create CMakeLists.txt for your unit tests
 at swift/unittests//CMakeLists.txt 
 with add_swift_unittest function that 
 defines the source files, executable name and dependencies
 4. add add_subdirectory call to swift/unittests/CMakeLists.txt 
 How to add unit tests?

Slide 57

Slide 57 text

No content

Slide 58

Slide 58 text

No content

Slide 59

Slide 59 text

1. create tool in swift/tools/
 2. (not required, but a good idea) create library 
 for the underlying logic 
 in swift/include/swift/ 
 and swift/lib/
 3. add unit tests to swift/unittests/
 4. add integration tests to swift/tests/
 How to create new compiler-based tool?

Slide 60

Slide 60 text

No content

Slide 61

Slide 61 text

Abstract 
 Syntax 
 Tree

Slide 62

Slide 62 text

CompilerInstance Compiler; CompilerInvocation Invocation; Invocation.setModuleName(ModuleName); Invocation.setMainExecutablePath(MainExecutablePath); for (const auto &InputFilename : InputFilenames) { Invocation.addInputFilename(InputFilename); } Invocation.setFrameworkSearchPaths(FrameworkPaths); Invocation.setSDKPath(SdkPath); Invocation.setTargetTriple(Triple); if (Compiler.setup(Invocation)) { return stringError("Error during compiler setup"); } Compiler.performSema();

Slide 63

Slide 63 text

class SymbolsWalker : public SourceEntityWalker { bool visitDeclReference(ValueDecl *, CharSourceRange, TypeDecl *, ExtensionDecl *, Type, ReferenceMetaData) override; } for (auto* Unit : Compiler.getMainModule() ->getFiles()) { if (auto* Current = dyn_cast(Unit)) { SymbolsWalker Walker; Walker.walk(&Current); } }

Slide 64

Slide 64 text

ParamDecl *Parameter = //given from SourceEntityWalker auto Name = Parameter ->getName().str().str(); CharSourceRange Range(Parameter ->getNameLoc(), Name.length());

Slide 65

Slide 65 text

auto &SourceManager = Current ->getASTContext().SourceMgr; auto BufferId = Current ->getBufferID().getValue();
 std ::error_code Error; llvm ::raw_fd_ostream DescriptorStream(Path, Error, F_None); SourceEditOutputConsumer Editor(SourceManager, 
 BufferId, DescriptorStream);
 
 CharSourceRange Range = // computed slide ago auto ReplacingString = // replacement for range in code Editor ->ide ::SourceEditConsumer ::accept(SourceManager, Range, ReplacingString);

Slide 66

Slide 66 text

No content

Slide 67

Slide 67 text

static llvm ::cl ::opt SymbolsJsonPath("symbolsjson", llvm ::cl ::desc("Name of the file containing extracted symbols"), llvm ::cl ::cat(ObfuscatorNameMapper)); int main(int argc, char *argv[]) { INITIALIZE_LLVM(argc, argv); llvm ::cl ::ParseCommandLineOptions(argc, argv, “obfuscator-name-mapper");

Slide 68

Slide 68 text

void MappingTraits :: mapping(IO &Io, SymbolsJson &Object) { Io.mapRequired("symbols", Object.Symbols); } Input Input(JsonString); SymbolsJson Symbols; Input >> Symbols;

Slide 69

Slide 69 text

• LLVM Programmer’s Manual 
 (http://llvm.org/docs/ProgrammersManual.html) 
 • LLVM Coding Standards 
 (http://llvm.org/docs/CodingStandards.html) • many more!

Slide 70

Slide 70 text

1. Get familiar with C++11 Few last practical tips

Slide 71

Slide 71 text

1. Get familiar with C++11
 2. Use Xcode as IDE (works really well!) Few last practical tips

Slide 72

Slide 72 text

1. Get familiar with C++11
 2. Use Xcode as IDE (works really well!)
 3. Keep Swift compiler in sync 
 with Xcode version Few last practical tips

Slide 73

Slide 73 text

1. Get familiar with C++11
 2. Use Xcode as IDE (works really well!)
 3. Keep Swift compiler in sync 
 with Xcode version
 4. Don’t let the lack of compiler knowledge 
 scare you away! Few last practical tips

Slide 74

Slide 74 text

No content

Slide 75

Slide 75 text

Pros Cons Anything compiler can do, you can do too!

Slide 76

Slide 76 text

Pros Cons Anything compiler can do, you can do too! Compiler libs are designed for compilation, not for your tool

Slide 77

Slide 77 text

Pros Cons Anything compiler can do, you can do too! Compiler libs are designed for compilation, not for your tool So many tools are available!

Slide 78

Slide 78 text

Pros Cons Anything compiler can do, you can do too! Compiler libs are designed for compilation, not for your tool So many tools are available! No stable API, breaking changes all the time

Slide 79

Slide 79 text

Pros Cons Anything compiler can do, you can do too! Compiler libs are designed for compilation, not for your tool So many tools are available! No stable API, breaking changes all the time You can leverage 
 the existing infrastructure

Slide 80

Slide 80 text

Pros Cons Anything compiler can do, you can do too! Compiler libs are designed for compilation, not for your tool So many tools are available! No stable API, breaking changes all the time You can leverage 
 the existing infrastructure You must fit into 
 the existing infrastructure

Slide 81

Slide 81 text

Pros Cons Anything compiler can do, you can do too! Compiler libs are designed for compilation, not for your tool So many tools are available! No stable API, breaking changes all the time You can leverage 
 the existing infrastructure You must fit into 
 the existing infrastructure Support for both 
 Swift and Objective-C

Slide 82

Slide 82 text

Pros Cons Anything compiler can do, you can do too! Compiler libs are designed for compilation, not for your tool So many tools are available! No stable API, breaking changes all the time You can leverage 
 the existing infrastructure You must fit into 
 the existing infrastructure Support for both 
 Swift and Objective-C There might be better alternatives

Slide 83

Slide 83 text

Alternatives • libSyntax • SourceKit • existing swift tools

Slide 84

Slide 84 text

No content

Slide 85

Slide 85 text

• https://github.com/PolideaPlayground/ SiriusObfuscator-SymbolExtractorAndRenamer 
 • Documentation folder has a lot of notes 
 on various implementation decisions, 
 with details and motivation

Slide 86

Slide 86 text

No content

Slide 87

Slide 87 text

@KacperHarasim

Slide 88

Slide 88 text

Questions? @_siejkowski

Slide 89

Slide 89 text

Thank you!