Configuration File

XTD Protect for iOS Command Line Tools

This section describes the modifiable features of the configuration file. To learn how to create a default configuration file that you can edit, refer to Project setup.

Protection profile

XTD Protect for iOS can protect apps with either of two profiles:

  • Dynamic Profile: In this mode, security measures are applied by patching the original application, allowing it to remain largely unchanged. It provides robust security and has been optimized to be compatible with almost any app, so it is also useful in scenarios if any issues arise with the Regular Profile. By default, Dynamic Profile includes the following protections - these can be changed in the configuration file:
    • Anti-debugging
    • App properties protection
    • Resource deletion checks
    • Resource protection
    • Superchecks
    • Jailbreak detection
    • Environmental checks
    • XTD Detection and Response features in online mode
    • C-string obfuscation
  ...
  "user features": {
     "protection profile": "dynamic",
  }
  ...
  • Regular Profile: This mode recompiles the application with additional protection code and supports all IOSdefender security features. Regular mode is recommended for maximum security.
...
"user features": {
   "protection profile": "regular",
}
...

String data encryption

Normally disassemblers such as IDA show strings and where they’re used, which can reveal details about otherwise obfuscated code.

IOSdefender uses string obfuscation to hide this information. String obfuscation is the process of encrypting the string at compile time and decrypting it at runtime. Since the string is no longer present in the executable this defeats basic static analysis. This makes it significantly harder for an attack to find and make use of strings that suggest the functionality of the executable.

Sometimes it may be necessary to exclude specific strings from obfuscation to ensure correct program behaviour.

If you would like to do so, create a plain text file where every line in the file is a regular expression set to match the strings that need to be excluded. For example,

exclusions.txt

Hello. _World._
Then this plain text file should be specified as the value for the string obfuscation string exclude filename setting in the project config file.

project.config

{
   "title": "Auto-generated config file",
   "pipeline": "binary",
   "revision": 2,
   "config": "project",
   "mode": "offline",
   "user features": {
   <...>
      "string obfuscation string exclude filename": "exclusions.txt",
   <...>
   }
}

Swift name obfuscation

By default, Swift class and descriptor names are not obfuscated. This feature is disabled because the archive may contain external references to these names from supporting files (e.g., storyboards, Lottie animation files, JavaScript). While the tool attempts to automatically identify and resolve these references, this is not always possible when files are encrypted or in unsupported formats. In such cases, obfuscating Swift names may cause runtime issues.

Verimatrix recommends thorough testing before releasing an application with this feature enabled.

If you would like to turn this feature on, set the enable swift name obfuscation to True.

project.config

{
   "title": "Auto-generated config file",
   "pipeline": "binary",
   "revision": 2,
   "config": "project",
   "mode": "offline",
   "user features": {
   <...>
      "enable swift name obfuscation": "True",
   <...>
   }
}

Protecting application secrets

The original obfuscation system is optimized towards the breadth of coverage - the tool attempts to obfuscate as many strings as possible without affecting performance. This system has a more advanced counterpart: stack based string obfuscation. It is a more secure, but also a more computationally expensive variant of string obfuscation. Using this system, strings are obfuscated on-demand rather than on startup, making it more suitable for the obfuscation of a smaller set of strings that contain application secrets and require a higher level of security.

Stack based string encryption can be activated using two settings. You can specify a comma-separated list of secrets as the value for the secrets strings setting which will ensure that the specified secrets will be get obfuscated using the more secure stack obfuscation method. Alternatively, if you have a high number of secrets, you can store them in a text file where each line is a regular expression that matches either a single secret or a set of secrets. This text file should then be specified in the secrets filename setting, similar to how the general string obfuscation system works.

secrets.txt

SecretApiKey.*
kvb_2193_1ac_secret

For the system to be active, you will also have to have the general string obfuscation enabled. That is, enable string obfuscation must be set to True.

project.config

{
   "title": "Auto-generated config file",
   "pipeline": "binary",
   "revision": 2,
   "config": "project",
   "mode": "offline",
   "user features": {
   <...>
      "secrets filename": "secrets.txt",
      "secrets strings": "Password123,secret657",
      "enable string obfuscation": "True",
   <...>
   }
}

WARNING: This security feature needs to be used with caution as overuse of it may cause a severe slowdown of the app. For example, if too many strings are obfuscated in this way, or if the strings are used in the hot path, the application will need to run decryption procedures every time it is encountered, introducing latency.

Root detection

XTD Protect for iOS injects security code which checks a range of system properties which can be used to identify common rooting techniques.

There are two variants of this feature - soft jailbreak detection and hard jailbreak detection. This can be set by specifying either soft or hard in the jailbreak setting of the project config file. It is also possible to disable this feature altogether by specifying setting jailbreak to off.

In soft mode, the back-end server is used to monitor the rooting status of the application, and developer set rules can be used to decide if a suspend instruction should be sent to the application. Root status reporting is always active and cannot be disabled. Soft jailbreak detection is not available in offline mode as it requires a connection to the back-end server.

When using the hard jailbreak mode, positive rooting detection will result in the application exiting.

Detection of common instrumentation frameworks

XTD Protect for iOS injects security code which checks a range of system properties which can be used to identify common instrumentation and hooking frameworks.

Detection of common instrumentation frameworks will result in the application exiting in both Online and Offline modes.

Protection of embedded frameworks and plugins

Embedded frameworks

Embedded frameworks that are found in the Frameworks/ directory within the main app can be protected by specifying their names in the protect frameworks field of the project configuration file. By default this will apply a basic level of protection which includes all the treatment an app would get, minus anti-tamper protection. For example, if code obfuscation was turned on in the config, it would apply to both the main app and all frameworks.

If you want to include anti-tamper protection for frameworks, you can do so by setting the framework check network coverage to min, std or max, however this comes at the cost of performance. See the Anti-tamper support section for more information on these settings.

It may not always be practical to protect all the frameworks that are embedded within an archive. Two settings apply to selecting frameworks for protection.

  • protect frameworks is used to specify which frameworks the protection should be applied to. The frameworks can be specified using a comma-separated list of the binary names, without the .framework extension. It’s also possible to specify a star character * to indicate that all frameworks need protection.
  • exclude binaries can be used to exclude binaries from protection which can come in handy if the * is specified in the other setting. This setting accepts a comma-separated list of values.

It may not always be practical to protect all the frameworks that are embedded within an archive due to performance reasons.

Scenario 1

You have an archive that contains frameworks that you want protect but it also includes a large, publicly-available framework that does not need protection. First, enable protection for all frameworks by setting the protect frameworks setting to *. Then, specify the name of the framework you want to exclude in the exclude binaries field.

project.config

"user features": {
   <...>
      "protect frameworks": "*",
      "exclude binaries": "OpenCV,Alamofire,Firebase"
   <...>
}

The above configuration would protect all frameworks except for OpenCV, Alamofire and Firebase.

Scenario 2

If there are one or two frameworks that need protection, it’s possible to apply protection only to those using the protect frameworks feature.

"user features": {
   <...>
      "protect frameworks": "SecureCrypto,PaymentsSDK",
      "exclude binaries": ""
   <...>
}

The above configuration will protect SecureCrypto and PaymentsSDK protected but will leave the others unaffected.

Application extensions (plugins)

Application extensions (.appex) can be protected to the same degree as embedded frameworks where the tool applies all the protection features that are enabled in the config, except for anti-tamper.

If you want to include anti-tamper protection for plugins, you can do so by setting the plugin check network coverage to min, std or max, however this comes at the cost of performance. See the Anti-tamper support section for more information on these settings.

Similar to embedded frameworks, there are two configuration options that can be used to control this feature.

project.config

"user features": {
   <...>
      "protect plugins": "*",
      "exclude binaries": ""
   <...>
}

The above configuration will protect all .appex plugins in the archive.

  • protect plugins is used to specify which plugins the protection should be applied to. The plugins can be specified using a comma-separated list of the binary names, without the .appex extension. It’s also possible to specify a star character * to indicate that all plugins need protection.
  • exclude binaries can be used to exclude binaries from protection which can come in handy if the * is specified in the other setting. This setting accepts a comma-separated list of values.

An example configuration that only protects two plugins called Notifications.appex and NewRelic.appex:

"user features": {
   <...>
      "protect plugins": "Notifications,NewRelic",
      "exclude binaries": ""
   <...>
}

An example configuration that protects all plugins except for Slow.appex:

"user features": {
   <...>
      "protect plugins": "*",
      "exclude binaries": "Slow"
   <...>
}

XCFrameworks

An XCFramework is a form of packaging for the distribution of libraries. These types of packages have an .xcframework file extension and are typically consumed by other application developers that want to integrate a library into their project.

XCFrameworks may contain three types of libraries.

  • Dynamic framework (.framework) - a dynamic library that is shipped alongside the application and is loaded at runtime.
  • Static library (.a) - a static library that gets statically linked into an application’s binary.
  • Mergeable library (.framework) - a dynamic library that can also be linked statically as it contains the necessary metadata to do so. See the official Mergeable Libraries documentation for more information.

The tool supports the protection of dynamic frameworks but will not attempt to protect static libraries or mergeable libraries. The tool will also skip frameworks that target unsupported architectures (e.g. x86_64) or platforms (e.g. iOS Simulator).

Converting a mergeable library to a dynamic library

If you want to convert your mergeable library to a dynamic library, set MERGEABLE_LIBRARY = NO in your build script or disable the Build Mergeable Library feature in your build settings under Linking - Mergeable Libraries.

Alternatively, you can use strip -x -no_atom_info MergaebleFrameworkBinary to convert a mergeable library to a dynamic after it has been built. The strip utility will remove the LC_ATOM_INFO load command and related metadata that makes a dynamic library mergeable.

Configuration differences

The protection process is largely the same as for .xcarchive packages, with all the framework-related configuration settings being applicable to both embedded frameworks and XCFrameworks.

The only difference is that an empty string (default) value for the protect frameworks setting is treated differently. In embedded framework protection, an empty string signifies that no frameworks were selected for protection, which effectively turns off framework protection. In XCFramework protection, an empty string is treated as a * (protect all frameworks). That is because it is never desireable to turn framework protection off for XCFrameworks which consist solely of frameworks.

It’s also important to highlight that the default values for antitampering (framework check network coverage) and constant obfuscation (framework constant obfuscation rate) are off and 0.0, respectively. If you want antitampering to be enabled, set the framework check network coverage to min, std or max. Be aware that this comes at the cost of performance. See the Anti-tamper support section for more information.

Security implications

Use of frameworks is inherently less secure than having all the code in a single application. A framework exposes multiple entry points that aid in the recovery of the control flow graph that attackers could use to deobfuscate the app.

At this time, XCFramework protection does not include instrumentation or jailbreak (anti-rooting) checks. If you need to ensure that an app that uses your framework does not run on jailbroken devices, please consider protecting the app itself.

Frameworks with dependencies

When preparing an XCFramework for distribution, it is a common practice not to embed any other dynamic framework dependencies in the final .xcframework package. That is to avoid the situation where an XCFramework includes a different version of a dependency than the consumer of the XCFramework uses, resulting in symbol conflicts at the linking stage. For example, if your XCFramework depends on the Firebase framework and you include it in the package, the consumer may have trouble if they are also using a different version of Firebase in their app.

For XTD Protect for iOS to protect a framework, it needs to be recompiled. In the final stage of recompilation all of its dependencies need to exist for us to be able to link the protected binary. If your .xcframework package does not include all the necessary dependencies, it will fail protection.

Protection Summary

The following 1 binary failed to protect:
   Framework: MySDK
      Failed to protect: has missing dependencies

The solution to this problem is to temporarily add the framework dependencies into the XXXXX.framework/Frameworks directory. There are two ways this can be accomplished:

  • Embed the dependencies via Xcode by selecting Embed & Sign or Embed Without Signing settings under the Frameworks and Libraries section of the General settings of your XCFramework target in Xcode for every dependency.
    Once the XCFramework has been rebuilt, you will notice that the new framework possesses a Frameworks directory. IOSdefender should now be able to protect the XCFramework. After protection the embedded frameworks can be deleted from the xcframework package, e.g. rm -r MySDK.xcframework/ios-arm64/MySDK.framework/Frameworks.
  • Do the copying manually or as part of the continuous integration process.
    Example:

Suppose that you have an XCFramework that packages 2 frameworks, one for iOS and one for iOS Simulator:

Starting point

bee@VMX % ls MySDK.xcframework/
   Info.plist                     ios-arm64                       ios-arm64_x86_64-simulator

bee@VMX % ls MySDK.xcframework/ios-arm64/
   MySDK.framework

bee@VMX % ls MySDK.xcframework/ios-arm64_x86_64-simulator/
   MySDK.framework

Assuming that MySDK.framework depends on Google’s Firebase SDK, (Firebase.framework), you will want to create a Frameworks folder under MySDK.xcframework/ios-arm64/MySDK.framework directory and move it there before starting the protection process.

Moving dependency into the XCFramework

bee@VMX % mkdir ./MySDK.xcframework/ios-arm64/MySDK.framework/Frameworks
bee@VMX % cp -r ./Firebase.framework ./MySDK.xcframework/ios-arm64/MySDK.framework/Frameworks/
bee@VMX % ls MySDK.xcframework/ios-arm64/MySDK.framework/Frameworks/
   Firebase.framework

Once this step is complete, you should be able to protect the framework. After protection you can remove the Frameworks folder from the final .xcframework package.

Removing frameworks

bee@VMX % rm -r ./MySDK.xcframework/ios-arm64/MySDK.framework/Frameworks

If you skip the removal step, your XCFramework would be considered an umbrella framework - a framework that contains other frameworks in its container. Umrella frameworks are discouraged by Apple. See Guidelines for Creating Frameworks for more information.

Protection of static libraries

Static libraries linked within the main executable are protected with the same level of security as the rest of binary.

Anti-tamper support

Anti-tamper is the key feature of XTD Protect for iOS which introduces a number of security checks to your application at build time. These checks monitor the application for any sign of changes made to the application and, when detected, the system can respond immediately to prevent further execution of the altered application. There are two types of checks:

  • Superchecks are app-wide checks that cover the entirety of the binary. They are run only once, at startup of the application. These checks ensure that the binary has not been modified prior to startup and have little to no impact on the performance of the application.
  • Runtime checks cover smaller areas of the binary and are run continuously as the binary performs its functions. These checks get injected into a set percentage of functions found in the binary, resulting in thousands of checks scattered across the whole application. The placement of runtime checks is randomised, therefore no two protections are the same which introduces variability, requiring attackers to redo their work every time a new build is produced. Unfortunately, since these checks are run as part of normal execution, they may slow down the application, especially if checks get injected into the hot path. The runtime check size limit is specified as a percentage, ensuring that the total size of runtime checks cannot exceed X% of the binary size (see the ‘Total runtime check size limit’ in the table below).

If the performance of the application is not satisfactory after turning on this feature, you can fine tune it by adjusting the check network coverage settings which are found in the project configuration file.

project.config

"user features": {
   <...>
      "check network coverage": "std",
      "framework check network coverage": "min",
      "plugin check network coverage": "min",
   <...>
}

The framework check network coverage and plugin check network coverage settings behave the same as the general check network coverage setting but they apply to frameworks and plugins only. If required, you can use these to adjust app performance.

Setting valueEffect on check insertionSuperchecksRuntime checksTotal runtime check size limitPerformance impact
offNo checks will be inserted.NoNo0%None
minMinimal checks to cover the entire app.YesNo0%Low
stdContinuous checks to cover the entire app.YesYes (50% of functions have checks inserted)2%Medium
maxAdditional checks for extra protection.YesYes (70% of functions have checks inserted)5%High

WARNING Turning this feature off comes at a severe loss of security. Do not disable it without a good reason.

Constant obfuscation

The constant obfuscation feature protects numerical constants that are used in the application by obfuscating their true value.

This additional security feature is disabled by default. To enable, set the constant obfuscation rate value to a number higher than zero no higher than 1.0.

Setting it to 0.0 will turn the feature off, a value of 0.1 will mean every 10th instruction involving a constant will be obfuscated, and so on. A good starting value is 0.25.

project.config

"user features": {
   <...>
      "constant obfuscation rate": "0.25",
      "framework constant obfuscation rate": "0.0",
      "plugin constant obfuscation rate": "0.0",
   <...>
}

The framework constant obfuscation rate and plugin constant obfuscation rate settings behave the same as the general constant obfuscation rate setting but they apply to frameworks and plugins only. If required, you can use these to adjust app performance.

Generally there are quite a few constants that are used implicitly at the lower levels of the application, therefore this feature can decrease the performance of the application significantly and should be used with caution.

Protection of application resources

The tool can protect selected application resources. Resource files located inside the archive can be safeguarded from being modified, replaced or deleted after installation on the device. The following types of files are protected.

Resource file typeFile extension
SQLite database.db
SQL database.sql
Raw data.dat
Images.jpg .jpeg .png .gif .svg
HTML / CSS.html .css
Javascript.js
JS Bundle.jsbundle
JSON.json
Plain text.txt
Audio / Video.mp3 .mp4 .mkv .wav
True Type Font.ttf
XML.xml
PostScript.ps
PDF.pdf
Office document.rtf .doc .docx .xls .xlsx
Apple Bundle Resource.nib

This feature does not provide encryption of resource files.

The feature is controlled by changing property values in the project config file. The resources are protected when enable app resources protection property is set to True. When enable app resource deletion check property is set to True, the application will be securely terminated if any protected resource files are detected missing at application startup.

{
   "enable app resources protection": "True",
   "enable app resource deletion check": "True"
}

Protection of application properties

The tool can protect application properties in the main Info.plist and embedded.mobileprovision files from being changed. Currently, the following properties are protected.

Info.plistembedded.mobileprovision
CFBundleIdentifierTeamName
CFBundleExecutableTeamIdentifier
CFBundleDisplayNameApplicationIdentifierPrefix
CFBundleName
DTCompiler

This feature is controlled by changing a property value in the project config file.

{
   "enable app properties protection": "True"
}

Protection of React Native applications

React Native applications are protected in the same way as ordinary iOS and tvOS applications. All described above Security Features are applied to the executable, application properties and resource files. JavaScript bundles, Node modules and graphical assets are protected from tampering but not encrypted.

Protection of Unity applications

Applications built using the Unity Game Engine can be protected, however only the main binary will receive a significant level of protection. In the case of a Unity app, this application is simply a loader for a much larger framework, therefore the level of protection will be low. The entirety of the app will still be guarded with instrumentation, jailbreak and resource checks.

Frida hooking prevention

Malicious actors may use Frida, a dynamic instrumentation toolkit, to reverse engineer and attack your app. Such attacks often begin by hooking a function or set of functions within the app.

To counter this, the tool includes two Frida-specific countermeasures:

  • Environment Monitoring: Periodic system checks run throughout the app’s lifetime, monitoring for signs of instrumentation. If detected, the app is terminated, and in online mode, a report is sent to the monitoring server before exiting. This countermeasure is always active.
  • Scratch Register Scrambling: Additional layer of protection which thwarts this attack by scrambling the scratch registers that Frida relies on. If an attacker tried to instrument a function with scrambled scratch registers, Frida would fail to attach, stopping the attack in its tracks. While this ensures protection of all functions found in the executable, system libraries are unaffected and can still be hooked. Therefore, a combined approach of the two countermeasures is used when this feature is enabled.

NOTE: When this feature is used in online mode, hooking attempts may not be communicated to the analytics server as Frida will not be able to attach to the process in the first place. It is recommended to use this setting in offline mode as it adds an extra layer of protection.

This additional security feature is disabled by default. To enable, set the enable frida hooking prevention to True:

"user features": {
   <...>
      "enable frida hooking prevention": "True",
   <...>
}

Anti-debug support

When anti-debug support is enabled, we inject code that detects an attached debugger. If an attacker starts the application in a debugger or tries to attach to a running application secured by this feature, the application will exit immediately.

This additional security feature is disabled by default. To enable, set the anti debug rate value to a number higher than zero no higher than 1.0.

Setting it to 0.0 will turn the feature off, a value of 0.1 will mean every 10th function will be protected, and so on. A good starting value is 0.1.

project.config

"user features": {
   <...>
      "anti debug rate": "0.1",
      "framework anti debug rate": "0.0",
      "plugin anti debug rate": "0.0",
   <...>
}

The framework anti debug rate and plugin anti debug rate settings behave the same as the general anti debug rate setting but they apply to frameworks and plugins only.

Disassembly barrier

The disassembly barrier injects code into functions that attempts to confuse disassemblers converting assembly into C code. If successful, the code generation will fail, or the disassembler will be unable to detect a function at the given location.

This additional security feature is disabled by default. To enable, set the disassembly barrier rate value to a number higher than zero no higher than 1.0.

Setting it to 0.0 will turn the feature off, a value of 0.1 will mean every 10th function will be protected, and so on. A good starting value is 0.1.

"user features": {
   <...>
      "disassembly barrier rate": "0.1",
      "framework disassembly barrier rate": "0.0",
      "plugin disassembly barrier rate": "0.0",
   <...>
}

The framework disassembly barrier rate and plugin disassembly barrier rate settings behave the same as the general disassembly barrier rate setting but they apply to frameworks and plugins only.

URL detection in binaries

At protection time, the tool analyses every binary in the archive that has been selected for protection in an attempt to identify strings that look like URLs. After the protection is completed, the list of URLs is saved in a JSON file, urls.json, which can be found in the output directory. You will also see a message in the protection summary that will point you to this file:

Protection summary

We detected a number of URLs the archive and saved them in /Users/demo/out/urls.json for further inspection.
   RenderASCII.app: 3 URLs
   ThirdParty.framework: 16 URLs

The JSON file contains a list of targets and a list of URLs that have been located in the binary:

urls.json

[
   {
      "target": "RenderASCII.app",
      "urls": [
            "http://hackers-nest.com/stolen-secrets-endpoint",
            "http://crl.apple.com/root.crl0",
            "https://www.apple.com/appleca/0"
      ]
   }
]

You can find a schema for this JSON file in ~/Library/iosdefender/config/schemas/urls-schema.json.

The purpose of this analysis is to locate potentially malicious URLs in your app which may come in unexpectedly from 3rd party vendors. URL detection is disabled by default. If you want to use this feature, it can be turned on by setting the enable url detection setting to True:

"user features": {
   <...>
      "enable url detection": "True"
   <...>
}

Fine tuning for security or performance

If the performance of the protected app is not satisfactory, or if you want to increase the level of protection, you can fine tune some of the protection settings.

There are two security features that have a high impact on protected application performance.

Javascript assets encryption

If your application is WebView-based, you can enable this feature to encrypt local JavaScript sources. The tool scans for .html files in the archive and identifies \<script> tags referencing local JavaScript files. These referenced JavaScript files are encrypted and included in the output archive. They will be decrypted at runtime, on demand.

For example:

index.html

  <...>
  <script src="js/jquery.js"></script>
  <...>

The configuration below will make js/jquery.js encrypted and change it name to a randomised value e.g.js/ru0212.js.

project.config

"user features": {
   <...>
      "enable javascript encryption": "True",
   <...>
}

XTD threat detection callbacks

When an application is protected in “online” mode, it communicates with Verimatrix monitoring servers to provide real-time information on the application’s status. Every threat is reported, allowing app developers to remotely disable specific instances of the app.

This functionality can be enhanced further. With the help of an additional library, custom actions can be defined to respond to detected threats. For example, if XTD detects that the app is running on a jailbroken device, instead of shutting down, it can send a message to the app, alerting it of the jailbreak status. The app could then lock itself down and inform the user that it cannot be run on jailbroken devices instead of just terminating.

To enable this functionality, developers need to integrate the XTD Stub Library into their Xcode project. This library features a simple API with functions for setting the SPUID (unique identifier), registering a callback for receiving messages from XTD, and sending messages to XTD.

The library consists of placeholder function implementations, which are replaced with real implementations during the protection process. It supports both Swift and Objective-C applications. For integration examples, refer to the XTD Stub Library Examples repository which can be found in ~/Library/iosdefender/repos/xtd-stublib-examples.

Integrating the XTD stub library into your project

The stub library can be easily integrated using the Swift Package Manager in five steps:

  1. Open your project in Xcode and right-click on it in the Project Navigator.
  2. Select Add Package Pependencies...
  3. Press the Add Local… button. In the Finder window, navigate to ~/Library/iosdefender/repos/, select the xtd-stublib directory and press Add Package.
  4. Include the header XTDStubLib.h in your Objective C or Swift project, e.g. #import "XTDStubLib.h".
  5. For Swift projects the XTDStubLib.h header must be put in your project’s bridging header. An example bridging header XTDStubLibTestApp-Bridging-Header.h is provided with the sample Swift project.

If you’re not using SPM, you can manually integrate the library using examples found in /Library/iosdefender/sail/stublib.

API Overview

The XTD stub library API provides three key methods in XTDStubLib.h:

Set SPUID

// Sets the SPUID value for the running instance
+ (BOOL) setSPUID:(NSString *) spuidJSON
            error:(out NSError **) outError;

Register callback

// Registers a callback for receiving messages from the XTD system
+ (void) registerCallback:(XTDStubLibCallback) callback

Send message to XTD

// Sends a command to the server XTD ARC server
+ (BOOL) sendMessage:(NSString *) messageJSON
               error:(out NSError **) outError;

Refer to XTDStubLibTestAppContentView.swift in ~/Library/iosdefender/repos/xtd-stublib-examples/XTDStublibTestApp/ for an example of how to use these methods in Swift code.

See ViewController.m and XTDUtils.m in ~/Library/iosdefender/repos/xtd-stublib-examples/XTDStubLibTestAppObjC/ for an example of how to use these methods in Objective-C code.