iXGuard

April 16, 2025 ยท View on GitHub

https://www.guardsquare.com/ixguard

Proprietary mobile iOS code obfuscation tool to make it difficult to disassemble your .ipa.

This protects against intellectual property theft and credential harvesting of things like API keys that may be embedded in applications.

Install

Get the installer from iXGuard and then run the .pkg to install to the / root filesystem:

sudo installer -pkg "iXGuard_4_12_4_stable_arm_64.pkg" -target /

Documentation

http://127.0.0.1:8998/index.html

Unfortunately the documentation is not public but installed and loaded locally using a local python webapp when you install the iXguard pkg.

The installer runs this command in the foreground in a new terminal:

ixguard-docs

This is just a shell script /Library/iXGuard/scripts/ixguard-docs that calls:

#!/usr/bin/env sh
SCRIPT_PATH=`readlink -f "${BASH_SOURCE:-\$0}"`
SCRIPT_DIR=`dirname $SCRIPT_PATH`
xcrun python3 $SCRIPT_DIR/../python/server.py &> /dev/null

This is equivalent to this, because server.py does not have a shebang header line:

python3 /Library/iXGuard/python/server.py

Then you can open the docs at this link (should open automatically in default browser):

http://127.0.0.1:8998/index.html

This self-hosted doc site is made using MKDocs Material theme.

Usage

Sample Config

HariSekhon/Templates - ixguard.yaml:

license:
  - "./ixguard-license.txt"
debug:
  verbosity: info
  autoconfigure: false
protection:
  enabled: true
  names:
    enabled: false
  arithmetic-operations:
    enabled: true
  control-flow:
    enabled: true
  data:
    enabled: true
  code-integrity:
    enabled: false
  environment-integrity:
    enabled: false
  resources:
    enabled: false
export:
  embed-bitcode: false

Build IPA with BitCode

This is neccessary to build an IPA with both bitcode and machine code that iXGuard can later run on.

You can activate it with the -toolchain com.guardsquare.ixguard argument to xcodebuild, eg:

xcodebuild archive \
           -workspace "$APP".xcworkspace \
           -scheme SIT \
           -configuration SIT \
           -archivePath "$ARCHIVE_PATH" \
           -toolchain com.guardsquare.ixguard \
           -quiet

or just set this environment variable before running xcodebuild or Fastlane:

export TOOLCHAINS="com.guardsquare.ixguard"

If you get this error message, it's caused by

xcodebuild -exportArchive

breaks with:

error: exportArchive: Rsync failed

Then you need to skip creating the archive and instead run ixguard on the .xcarchive instead.

ixguard --config ixguard.yaml --local --force -o ./build/MyApp-Guarded.xcarchive  ./build/MyApp.xcarchive

And then run the xcodebuild -exportArchive afterwards.

Optional: Check BitCode is present

Check xcarchive was generated with BitCode

NAME=MyApp
otool -l "$NAME.xcarchive//Products/Applications/$NAME.app/$NAME" | grep -A2 __LLVM

or

Check IPA was generated with BitCode

NAME=MyApp
unzip "$NAME.ipa"
otool -l "Payload/$NAME.app/$NAME" | grep -A2 __LLVM

If the output shows a __LLVM section, like this, then bitcode is included:

sectname __LLVM
segname  __TEXT

The IPA file size will also be larger than it would otherwise.

Run iXGuard to generate new Hardened Code

Run iXGuard to generate Hardened xcarchive

NAME=MyApp
ixguard --config ixguard.yaml --local --force -o "./build/$NAME-Guarded.xcarchive"  "./build/$NAME.xcarchive"

And then run the xcodebuild -exportArchive afterwards.

See the Fastlane template.

or

Run iXGuard to generate Hardened IPA

IPA="MyApp.ipa"

Create a variable name for the new output IPA to be the same as the original except with -hardened.ipa suffix, eg. -> MyApp-hardened.ipa:

HARDENED_IPA="${IPA_PATH%.ipa}-hardened.ipa"

Run ixguard on the .ipa archive to generate a new hardened ipa:

ixguard --config "$IXGUARD_CONFIG" --local -o "$HARDENED_IPA" "$IPA_PATH"

This takes several minutes to run and generates MyApp-hardened.ipa.

The --local switch skips checking for updates and prevents the build breaking with this error if your wifi is down:

Generating usage statistics failed: Network error.
Failed to check for updates due to a network issue. Use the -local flag to run ixguard without checking for updates.

Log & Stats

iXGuard Log

An ixguard.log file will be created at the root of the git repo containing logs and a statistics block like this:

iXGuard Stats

STATISTICS:
-----------

Name Obfuscation:
-----------------
  - Symbols hidden: 36228
  - Symbols obfuscated: 116398
  - Entities renamed: 16226
  - Entities skipped because they are part of the SDK: 565571
  - Entities skipped because of blacklist: 11410
  - Entities skipped because they were used in reflection: 12

Arithmetic Obfuscation:
-----------------------
  - Functions skipped because they were not whitelisted: 37888

Control Flow Obfuscation:
-------------------------
  - Dlsymified calls to this function: 0
  - Skipped due to not linked: 6
  - Skipped due to not being externally linked: 36680
  - Functions not obfuscated because they were not whitelisted: 31327
  - Function locations reordered: 38044
  - Global locations reordered: 177554

Integrity:
----------

Asset Encryption:
-----------------
  - Resources skipped because they were not whitelisted: 896

Fastlane Stats

iXGuard will more than double your build time:

[01:36:09]: ๐ŸŽ‰ Built with ixGuard toolchain and exported hardened IPA successfully!

+------------------------------------------------------------------------------------+
|                                  fastlane summary                                  |
+------+---------------------------------------------------------------+-------------+
| Step | Action                                                        | Time (in s) |
+------+---------------------------------------------------------------+-------------+
| 1    | opt_out_usage                                                 | 0           |
| 2    | default_platform                                              | 0           |
| 3    | setup_ci                                                      | 0           |
| 4    | get_build_number                                              | 0           |
| 5    | git_branch                                                    | 0           |
| 6    | last_git_tag                                                  | 0           |
| 7    | ensure_git_branch                                             | 0           |
| 8    | build_app                                                     | 546         |
| 9    | cd .. && ixguard --config ixguard.yaml --local --force -o "./ | 725         |
| 10   | build_app                                                     | 75          |
+------+---------------------------------------------------------------+-------------+

[01:36:09]: fastlane.tools just saved you 22 minutes! ๐ŸŽ‰

Check

Check your resulting .ipa using Mac Binary Debugging tools like:

:octocat: gdbinit/MachOView

CI/CD Install

https://www.guardsquare.com/blog/continuously-protecting-your-ios-project-in-a-cloud-based-ci

curl https://downloads.guardsquare.com/cli/latest_macos_amd64 -sL |
tar -x &&
sudo mv -i guardsquare /usr/local/bin/

You need an SSH key which has been uploaded to the iXGuard portal to authenticate this download:

guardsquare --ssh-agent download ixguard -o ixguard.pkg
sudo installer -pkg ixguard.pkg

Then put your license file and ixguard.yml config to your CI/CD, the former via secret injection, the latter can be committed to Git.