[iOS reverse engineering and security] Use ollvm to obfuscate your source code_

Foreword

When you are studying other people’s source code, do you expect that other people’s code will not be protected or obfuscated in any way? At this time, should you consider the security of your own code? This article will tell you how to use ollvm to obfuscate the iOS code [This article is an introductory post].

If you are interested in getting started with network security, you can click here if you need it Big benefits of network security: Getting started & advanced full set of 282G learning resource package to share for free!

1. Goal

Compile the ollvm tool and obfuscate your ipa or dynamic library in Xcode to increase the difficulty for others to crack your source code.

2. Tools

  • ollvm: Download address: https://github.com/heroims/obfuscator
  • Xcode: iOS development tools

3. Steps

1. Basic knowledge

LLVM

LLVM (Low Level Virtual Machine) is an open source compiler infrastructure that includes a set of modular, reusable compilers and tools that supports multiple programming languages and target architectures, including x86, ARM, and MIPS. LLVM was originally developed by Professor Chris Lattner at the University of Illinois at Urbana–Champaign and is now maintained and developed by the LLVM community.

The core idea of LLVM is to divide the compiler into two parts: front-end and back-end. The front-end is responsible for converting the source code into an intermediate representation (IR), and the back-end is responsible for converting the intermediate representation into assembly code for the target machine. This design allows LLVM to support multiple programming languages because only one front-end needs to be written for each language, and the back-end’s versatility can be used to support multiple target architectures.

In addition to the compiler, LLVM also includes some tools, such as optimizers, debuggers, assemblers, and disassemblers. These tools can help developers better analyze and debug programs, and improve the performance and reliability of the code.

LLVM has become a widely used compiler infrastructure, and many programming languages and tool chains use LLVM as the backend, such as C, C++, Objective-C, Swift, Rust, Go, etc. LLVM is also widely used in computer architecture research, code security analysis, machine learning and other fields.

Clang

Clang is a C, C++, Objective-C and Objective-C++ compiler based on the LLVM framework. It is an open source project developed and maintained by the LLVM community. Clang is designed to provide high-quality diagnostics, fast compilation speed, low memory footprint, and good portability.

Clang’s compiler front-end uses a modern compiler architecture, including syntax analysis based on lexical analyzers and syntax analyzers, generating abstract syntax trees (AST) and performing type checking and semantic analysis. The optimization and parallelization of these steps allows Clang to compile quickly, while providing better error and warning information, helping developers find and fix problems in the code faster.

In addition to being a standalone compiler, Clang can also be used as a library for other tools, such as static analysis tools, editor plug-ins, and code refactoring tools. Clang’s modular design and good API allow it to be easily integrated into other tools, providing a better programming experience.

Due to Clang’s excellent performance and good design, it has become the preferred compiler for many projects, such as LLVM itself, the default compiler for macOS and iOS, etc. At the same time, many developers and organizations are also actively developing and contributing Clang code, leaving it with broad room for development in the future.

OLLVM

OLLVM (Obfuscator-LLVM) is an obfuscator based on the LLVM framework, which can obfuscate programs to improve program security. The design goal of OLLVM is to provide a flexible and customizable obfuscation solution that makes it more difficult for attackers to understand and analyze program behavior.

OLLVM achieves the obfuscation effect by performing various obfuscation operations on the program, such as code replacement, function inlining, control flow flattening, encryption, etc. These obfuscation operations can change the control flow graph and data flow graph of the program, making the program more difficult to understand and reverse analyze. At the same time, OLLVM also provides some additional security mechanisms, such as encrypting program strings, using stack protection and position-independent code, etc., to increase program security.

Since OLLVM is developed based on the LLVM framework, it can be integrated with existing LLVM tools and compilers, such as Clang and LLDB, etc. This allows developers to easily use OLLVM in existing development environments and use existing tools to debug and analyze obfuscated programs.

Although the main purpose of OLLVM is to improve program security, it can also be used in other areas, such as code protection, code compression, and code optimization. Due to its flexibility and customizability, OLLVM has been widely used in many fields, such as network security, game development, and finance.

The pass between IRs is where the obfuscator works. The relevant code is located at obfuscator/llvm/lib/Transforms/Obfuscation/

2. Compile ollvm

The command is as follows:

witchan@witchandeMacBook-Air ~ % git clone -b llvm-13.x https://github.com/heroims/obfuscator.git
witchan@witchandeMacBook-Air ~ % $cd obfuscator
witchan@witchandeMacBook-Air ~ % mkdir build
witchan@witchandeMacBook-Air ~ % cd build
witchan@witchandeMacBook-Air ~ % cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_CREATE_XCODE_TOOLCHAIN=ON -DLLVM_ENABLE_PROJECTS="clang;libcxx;libcxxabi" -DLLVM_ENABLE_NEW_PASS_MANAGER=OFF ../llvm
witchan@witchandeMacBook-Air ~ % make -j8
witchan@witchandeMacBook-Air ~ % sudo make install-xcode-toolchain
witchan@witchandeMacBook-Air ~ % mv /usr/local/Toolchains /Library/Developer/

Note: make -j8 The compilation speed of this command depends on your hardware device.

After executing the above commands one by one, ollvm will be compiled and installed. The effect is as follows:

3. Confusion command and effect comparison

Introduction to obfuscated commands

  • fla: This option uses function-level obfuscation to hide the structure of the program. This is accomplished by randomly renaming functions, adding unnecessary control flow, and removing called functions. This increases the difficulty of decompiling and analyzing the code.
  • bcf: This option uses basic block level obfuscation to hide the structure of the code. This is accomplished by changing the control flow between basic blocks, adding unnecessary basic blocks, and removing conditional branches between basic blocks.
  • -sub: This option uses string obfuscation to hide constant strings in your code. This is accomplished by breaking the string into small chunks, storing them in an array, and reassembling them at runtime. This makes it more difficult to analyze code and find sensitive information.
  • split: This option uses control flow obfuscation to increase program complexity. This is accomplished by dividing the function into several basic blocks, adding random jump instructions, and randomly reorganizing these basic blocks at runtime. This makes the flow of the code more difficult to trace, making it more difficult to crack and decompile.
  • sobf: This option uses source code obfuscation technology to hide the logic and structure of the code. This transforms the code using encryption-like means, making it difficult to understand and analyze. This can be performed via runtime decryption, thus hiding the true functionality of the code.

The sample code is as follows:

- (void)testMethod {
    NSString *name = @"wit";
    int age = 18;
 
    NSArray *list = @[@1,@3,@5,@18];
    for (int i=0; i<list.count; i + + ) {
        int value = [list[i] intValue];
        if (value == age) {
            age + = 10;
            name = @"chan";
        }
    }
    NSLog(@"name = %@", name);
    NSLog(@"age = %d", age);
}

Obfuscation not used:

__int64 __fastcall -[ViewController testMethod](__int64 a1, __int64 a2)
{
  void *v2; // x0
  __int64 v3; // ST70_8
  void *v4; // x0
  __int64 v5; // ST68_8
  void *v6; // x0
  __int64 v7; // ST60_8
  void *v8; // x0
  __int64 v9; // ST58_8
  void *v10; // x0
  void *v11; // x0
  void *v12; // ST20_8
  int v13; // ST2C_4
  __int64 result; // x0
  int i; // [xsp + 7Ch] [xbp-54h]
  void *v16; // [xsp + 80h] [xbp-50h]
  int v17; // [xsp + 8Ch] [xbp-44h]
  __int64 v18; // [xsp + 90h] [xbp-40h]
  __int64 v19; // [xsp + 98h] [xbp-38h]
  __int64 v20; // [xsp + A0h] [xbp-30h]
  __int64 v21; // [xsp + A8h] [xbp-28h]
  __int64 v22; // [xsp + B0h] [xbp-20h]
  __int64 v23; // [xsp + B8h] [xbp-18h]
  __int64 v24; // [xsp + C0h] [xbp-10h]
  __int64 v25; // [xsp + C8h] [xbp-8h]
 
  v25 = *(_QWORD *)__stack_chk_guard_ptr;
  v20 = a1;
  v19 = a2;
  v18 = objc_retain( & amp;stru_100008078);
  v17 = 18;
  v2 = objc_msgSend(off_10000D2D0, (const char *)off_10000D290, 1LL);
  v3 = objc_retainAutoreleasedReturnValue(v2);
  v21 = v3;
  v4 = objc_msgSend(off_10000D2D0, (const char *)off_10000D290, 3LL);
  v5 = objc_retainAutoreleasedReturnValue(v4);
  v22 = v5;
  v6 = objc_msgSend(off_10000D2D0, (const char *)off_10000D290, 5LL);
  v7 = objc_retainAutoreleasedReturnValue(v6);
  v23 = v7;
  v8 = objc_msgSend(off_10000D2D0, (const char *)off_10000D290, 18LL);
  v9 = objc_retainAutoreleasedReturnValue(v8);
  v24 = v9;
  v10 = objc_msgSend(off_10000D2D8, (const char *)off_10000D298, & amp;v21, 4LL);
  v16 = (void *)objc_retainAutoreleasedReturnValue(v10);
  objc_release(v9);
  objc_release(v7);
  objc_release(v5);
  objc_release(v3);
  for ( i = 0; i < (unsigned __int64)objc_msgSend(v16, (const char *)off_10000D2A0); + + i )
  {
    v11 = objc_msgSend(v16, (const char *)off_10000D2A8, i);
    v12 = (void *)objc_retainAutoreleasedReturnValue(v11);
    v13 = (unsigned __int64)objc_msgSend(v12, (const char *)off_10000D2B0);
    objc_release(v12);
    if ( v13 == v17 )
    {
      v17 + = 10;
      objc_storeStrong( & amp;v18);
    }
  }
  NSLog( &stru_1000080B8);
  NSLog( &stru_1000080D8);
  objc_storeStrong( & amp;v16);
  result = objc_storeStrong( & amp;v18);
  *(_QWORD *)__stack_chk_guard_ptr;
  return result;
}

Turn on ollvm obfuscation:

Obfuscated parameters: -mllvm -fla -mllvm -bcf -mllvm -sub -mllvm -split -mllvm -sobf

The effect after confusion is as follows:

__int64 __fastcall -[ViewController testMethod](__int64 a1, __int64 a2)
{
  void *v2; // x0
  void *v3; // x0
  __int64 v4; // ST58_8
  void *v5; // x0
  __int64 v6; // ST50_8
  void *v7; // x0
  __int64 v8; // ST48_8
  void *v9; // x0
  void *v10; // x0
  signed int v11; // w8
  BOOL v12; // w9
  signed int v13; // w8
  BOOL v14; // w9
  signed int v15; // w8
  BOOL v16; // w14
  signed int v17; // w8
  void *v18; // x0
  void *v19; // ST20_8
  int v20; // ST2C_4
  BOOL v21; // w12
  signed int v22; // w8
  BOOL v23; // w9
  signed int v24; // w8
  BOOL v25; // w12
  signed int v26; // w8
  signed int v27; // w8
  BOOL v28; // w9
  signed int v29; // w8
  BOOL v30; // w12
  signed int v31; // w8
  BOOL v32; // w14
  signed int v33; // w8
  BOOL v34; // w9
  signed int v35; // w8
  void *v37; // x0
  void *v38; // ST08_8
  int v39; // ST14_4
  signed int v40; // [xsp + 94h] [xbp-DCh]
  int v41; // [xsp + 98h] [xbp-D8h]
  int v42; // [xsp + 9Ch] [xbp-D4h]
  void *v43; // [xsp + A0h] [xbp-D0h]
  int v44; // [xsp + ACh] [xbp-C4h]
  __int64 v45; // [xsp + B0h] [xbp-C0h]
  __int64 v46; // [xsp + B8h] [xbp-B8h]
  __int64 v47; // [xsp + C0h] [xbp-B0h]
  __int64 v48; // [xsp + C8h] [xbp-A8h]
  __int64 *v49; // [xsp + D0h] [xbp-A0h]
  const char *v50; // [xsp + D8h] [xbp-98h]
  void *v51; // [xsp + E0h] [xbp-90h]
  __int64 v52; // [xsp + E8h] [xbp-88h]
  unsigned __int64 v53; // [xsp + F0h] [xbp-80h]
  const char *v54; // [xsp + F8h] [xbp-78h]
  void *v55; // [xsp + 100h] [xbp-70h]
  void *v56; // [xsp + 108h] [xbp-68h]
  __int64 v57; // [xsp + 110h] [xbp-60h]
  bool v58; // [xsp + 11Fh] [xbp-51h]
  __int64 *v59; // [xsp + 120h] [xbp-50h]
  int v60; // [xsp + 128h] [xbp-48h]
  int v61; // [xsp + 12Ch] [xbp-44h]
  __int64 v62; // [xsp + 130h] [xbp-40h]
  __int64 v63; // [xsp + 138h] [xbp-38h]
  __int64 v64; // [xsp + 140h] [xbp-30h]
  __int64 v65; // [xsp + 148h] [xbp-28h]
  __int64 v66; // [xsp + 150h] [xbp-20h]
  __int64 v67; // [xsp + 158h] [xbp-18h]
 
  v67 = *(_QWORD *)__stack_chk_guard_ptr;
  v47 = a1;
  v46 = a2;
  v45 = objc_retain( & amp;stru_10000C078);
  v44 = 18;
  v2 = objc_msgSend(off_1000112D0, (const char *)off_100011290, 1LL);
  v48 = objc_retainAutoreleasedReturnValue(v2);
  v63 = v48;
  v49 = &v64;
  v50 = (const char *)off_100011290;
  v51 = off_1000112D0;
  v40 = -1933834049;
  while(1)
  {
    while(1)
    {
      while(1)
      {
        while(1)
        {
          while(1)
          {
            while(1)
            {
              while(1)
              {
                while ( v40 == -1944675086 )
                {
                  v23 = x_24 * (x_24 - 1) % 2u == 0;
                  if ( ((unsigned __int8)v23 & amp; (y_25 < 10) | v23 ^ (y_25 < 10)) & amp; 1 )
                    v24 = -484710506;
                  else
                    v24 = -757913245;
                  v40 = v24;
                }
                if ( v40 != -1933834049 )
                  break;
                v3 = objc_msgSend(v51, v50, 3LL);
                v52 = objc_retainAutoreleasedReturnValue(v3);
                v40 = -1240448313;
              }
              if ( v40 != -1917278325 )
                break;
              v40 = 1916623537;
            }
            if ( v40 != -1863636706 )
              break;
            if(v58)
              v27 = -1295475565;
            else
              v27 = -706815919;
            v40 = v27;
          }
          if ( v40 != -1847141909 )
            break;
          v10 = objc_msgSend(v55, v54);
          if ( v53 >= (unsigned __int64)v10 )
            v11 = 1801130365;
          else
            v11 = 1380523063;
          v40 = v11;
        }
        if ( v40 != -1846767803 )
          break;
        v40 = -267481379;
      }
      if ( v40 != -1502917571 )
        break;
      v54 = (const char *)off_1000112A0;
      v55 = v43;
      v40 = -1847141909;
    }
    if (v40 == -1361227290)
      break;
    switch(v40)
    {
      case -1295475565:
        v44 + = 10;
        v40 = 1987329712;
        break;
      case -1240448313:
        v4 = v52;
        *v49 = v52;
        v5 = objc_msgSend(off_1000112D0, (const char *)off_100011290, 5LL);
        v6 = objc_retainAutoreleasedReturnValue(v5);
        v65 = v6;
        v7 = objc_msgSend(off_1000112D0, (const char *)off_100011290, 18LL);
        v8 = objc_retainAutoreleasedReturnValue(v7);
        v66 = v8;
        v9 = objc_msgSend(off_1000112D8, (const char *)off_100011298, & amp;v63, 4LL);
        v43 = (void *)objc_retainAutoreleasedReturnValue(v9);
        objc_release(v8);
        objc_release(v6);
        objc_release(v4);
        objc_release(v48);
        v42 = 0;
        v40 = -381231803;
        break;
      case -1088106110:
        v40 = -1361227290;
        break;
      case -1009849083:
        v61 = v60 + 1;
        v40 = -792637388;
        break;
      case -792637388:
        v42 = v61;
        v40 = -381231803;
        break;
      case -757913245:
        v40 = -484710506;
        break;
      case -706815919:
        v40 = 975706093;
        break;
      case -484710506:
        v58 = v41 == v44;
        v25 = x_24 * (x_24 - 1) % 2u == 0;
        if ( (!v25 ^ (y_25 >= 10) | (v25 & amp; & amp; y_25 < 10)) & amp; 1 )
          v26 = -1863636706;
        else
          v26 = -757913245;
        v40 = v26;
        break;
      case -381231803:
        v53 = v42;
        v40 = -1502917571;
        break;
      case -267481379:
        v56 = v43;
        v57 = v42;
        v14 = x_24 * (x_24 - 1) % 2u == 0;
        if ( ((unsigned __int8)v14 & amp; (y_25 < 10) | v14 ^ (y_25 < 10)) & amp; 1 )
          v15 = -1917278325;
        else
          v15 = -1846767803;
        v40 = v15;
        break;
      case 265667512:
        v60 = v42;
        v30 = x_24 * (x_24 - 1) % 2u == 0;
        if ( (!v30 ^ (y_25 >= 10) | (v30 & amp; & amp; y_25 < 10)) & amp; 1 )
          v31 = 1998138173;
        else
          v31 = 1042960370;
        v40 = v31;
        break;
      case 543048662:
        NSLog( &stru_10000C0B8);
        NSLog( &stru_10000C0D8);
        v34 = x_24 * (x_24 - 1) % 2u == 0;
        if ( ((unsigned __int8)v34 & amp; (y_25 < 10) | v34 ^ (y_25 < 10)) & amp; 1 )
          v35 = -1088106110;
        else
          v35 = 1393219629;
        v40 = v35;
        break;
      case 818848043:
        v37 = objc_msgSend(v56, (const char *)off_1000112A8, v57);
        v38 = (void *)objc_retainAutoreleasedReturnValue(v37);
        v39 = (unsigned __int64)objc_msgSend(v38, (const char *)off_1000112B0);
        objc_release(v38);
        v41 = v39;
        v40 = 1041770448;
        break;
      case 975706093:
        v28 = x_24 * (x_24 - 1) % 2u == 0;
        if ( ((unsigned __int8)v28 & amp; (y_25 < 10) | v28 ^ (y_25 < 10)) & amp; 1 )
          v29 = 265667512;
        else
          v29 = 1042960370;
        v40 = v29;
        break;
      case 1041770448:
        v18 = objc_msgSend(v56, (const char *)off_1000112A8, v57);
        v19 = (void *)objc_retainAutoreleasedReturnValue(v18);
        v20 = (unsigned __int64)objc_msgSend(v19, (const char *)off_1000112B0);
        objc_release(v19);
        v41 = v20;
        v21 = x_24 * (x_24 - 1) % 2u == 0;
        if ( (!v21 ^ (y_25 >= 10) | (v21 & amp; & amp; y_25 < 10)) & amp; 1 )
          v22 = 2069967268;
        else
          v22 = 818848043;
        v40 = v22;
        break;
      case 1042960370:
        v40 = 265667512;
        break;
      case 1146841418:
        v32 = x_24 * (x_24 - 1) % 2u == 0;
        if ( (v32 ^ (y_25 < 10) | (v32 & amp; & amp; y_25 < 10)) & amp; 1 )
          v33 = 543048662;
        else
          v33 = 1393219629;
        v40 = v33;
        break;
      case 1380523063:
        v12 = x_24 * (x_24 - 1) % 2u == 0;
        if ( ((unsigned __int8)v12 & amp; (y_25 < 10) | v12 ^ (y_25 < 10)) & amp; 1 )
          v13 = -267481379;
        else
          v13 = -1846767803;
        v40 = v13;
        break;
      case 1393219629:
        NSLog( &stru_10000C0B8);
        NSLog( &stru_10000C0D8);
        v40 = 543048662;
        break;
      case 1801130365:
        v62 = v45;
        v40 = 1146841418;
        break;
      case 1916623537:
        v16 = x_24 * (x_24 - 1) % 2u == 0;
        if ( (v16 ^ (y_25 < 10) | (v16 & amp; & amp; y_25 < 10)) & amp; 1 )
          v17 = 1041770448;
        else
          v17 = 818848043;
        v40 = v17;
        break;
      case 1987329712:
        v59 = &v45;
        v40 = 2123926658;
        break;
      case 1998138173:
        v40 = -1009849083;
        break;
      case 2069967268:
        v40 = -1944675086;
        break;
      case 2123926658:
        objc_storeStrong(v59);
        v40 = -706815919;
        break;
    }
  }
  objc_storeStrong( & amp;v43);
  return objc_storeStrong( & amp;v45);
}

Summary

A simple introductory article, I hope it can help you.

Finally, we have prepared a big gift package for everyone!

Study plan arrangement


I have divided them into six stages in total, but it does not mean that you have to learn them all before you can start working. For some entry-level positions, it is enough to learn the third and fourth stages~

Here I have integrated and compiled a [282G] network security information package from basic entry to advanced. Friends who need it can scan the CSDN official cooperation QR code below to get it for free. Share it for free! ! !

If you are interested in getting started with cybersecurity, you can

Click hereThe major benefits of network security: entry & advanced full set of 282G learning resource package for free sharing!

①Network security learning route
②Hundreds of penetration testing e-books
③Security Attack and Defense 357 pages of notes
④50 Security Offense and Defense Interview Guides
⑤Security Red Team Penetration Toolkit
⑥Summary of experience in HW network protection operations
⑦100 practical cases of vulnerabilities
⑧Internal video resources of major security manufacturers
⑨Analysis of past CTF capture the flag competition questions