Swift compiler as a library: obfuscator case

Swift compiler as a library: obfuscator case

Presented during Mobile Warsaw meetup on 22nd of May 2018

43d2bef703ec7165166f161f137ac54f?s=128

Krzysztof Siejkowski

May 22, 2018
Tweet

Transcript

  1. 2.

    In software development, obfuscation is the deliberate act of creating

    source or machine code that is difficult for humans to understand — Wikipedia
  2. 5.

    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
  3. 6.

    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
  4. 7.

    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
  5. 8.
  6. 9.
  7. 10.
  8. 11.
  9. 12.

    class MyViewController: UIViewController {} class MyView: UIView {} class MyModel:

    NSManagedObject {} class MyRuntimeUsingObject: NSObject {} class SomeClass { @objc func someFunc() {} }
  10. 13.

    Obfuscation is more than symbol renaming 
 Code Obfuscation Techniques

    for Software Protection
 —PhD thesis by Jan Cappaert
 

  11. 19.
  12. 20.
  13. 23.

    Not universal tool… • no DSYM support • no multiple

    targets • no mixed Swift/Obj-C • not all Swift constructs supported
  14. 24.

    …but still powerful • Storyboards/XIBs renaming • various Swift expressions

    supported • excluding configuration • very easy to integrate
  15. 26.

    Xcode project Zobfuskowany Xcode project Command line interface (standalone or

    as Xcode build step) Original Xcode project Obfuscated Xcode project (copy or inplace)
  16. 27.

    Original Xcode project Xcode project parsing Symbols identification Generation of

    new names Obfuscated Xcode project (copy or inplace) Renaming in the source files
  17. 31.

    Original Xcode project Xcode project parsing Symbols identification Generation of

    new names Obfuscated Xcode project Renaming in the source files
  18. 32.

    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
  19. 33.

    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
  20. 34.
  21. 35.
  22. 36.
  23. 37.
  24. 38.
  25. 39.
  26. 40.
  27. 41.
  28. 42.

    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/<your-tool>/CMakeLists.txt 
 and define the source files, executable name and dependencies How to add new command line tool?
  29. 43.
  30. 44.
  31. 45.
  32. 46.
  33. 47.
  34. 48.
  35. 49.
  36. 50.

    1. create new folders in swift/include/swift and swift/lib
 2. add

    your .h interfaces 
 to swift/include/swift/<your-library>
 3. add your .cpp implementations to swift/lib/<your-library>
 4. create CMakeLists.txt for your library 
 at swift/lib/<your-library>/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?
  37. 51.
  38. 52.
  39. 53.
  40. 54.
  41. 55.
  42. 56.

    1. create new folder in swift/unittests
 2. add your .cpp

    test source code 
 to swift/unittests/<your-library>
 3. create CMakeLists.txt for your unit tests
 at swift/unittests/<your-library>/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?
  43. 57.
  44. 58.
  45. 59.

    1. create tool in swift/tools/<your-tool>
 2. (not required, but a

    good idea) create library 
 for the underlying logic 
 in swift/include/swift/<your-library> 
 and swift/lib/<your-library>
 3. add unit tests to swift/unittests/<your-library>
 4. add integration tests to swift/tests/<your-tool>
 How to create new compiler-based tool?
  46. 60.
  47. 62.

    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();
  48. 63.

    class SymbolsWalker : public SourceEntityWalker { bool visitDeclReference(ValueDecl *, CharSourceRange,

    TypeDecl *, ExtensionDecl *, Type, ReferenceMetaData) override; } for (auto* Unit : Compiler.getMainModule() ->getFiles()) { if (auto* Current = dyn_cast<SourceFile>(Unit)) { SymbolsWalker Walker; Walker.walk(&Current); } }
  49. 64.

    ParamDecl *Parameter = //given from SourceEntityWalker auto Name = Parameter

    ->getName().str().str(); CharSourceRange Range(Parameter ->getNameLoc(), Name.length());
  50. 65.

    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);
  51. 66.
  52. 67.

    static llvm ::cl ::opt<std ::string> 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");
  53. 69.

    • LLVM Programmer’s Manual 
 (http://llvm.org/docs/ProgrammersManual.html) 
 • LLVM Coding

    Standards 
 (http://llvm.org/docs/CodingStandards.html) • many more!
  54. 71.

    1. Get familiar with C++11
 2. Use Xcode as IDE

    (works really well!) Few last practical tips
  55. 72.

    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
  56. 73.

    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
  57. 74.
  58. 76.

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

    Compiler libs are designed for compilation, not for your tool
  59. 77.

    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!
  60. 78.

    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
  61. 79.

    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
  62. 80.

    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
  63. 81.

    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
  64. 82.

    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
  65. 84.
  66. 85.

    • https://github.com/PolideaPlayground/ SiriusObfuscator-SymbolExtractorAndRenamer 
 • Documentation folder has a lot

    of notes 
 on various implementation decisions, 
 with details and motivation
  67. 86.