Why Re-Signing iOS Apps is Better than Recompiling
Re-signing iOS apps allows you to open your app after it’s been built and modify everything except the application code. The main reason to use this process is to avoid recompiling an app and risking the introduction of unintended changes. Because modifying an app requires a code signature to be applied for a second time, the process is generally called re-signing.
Real World Re-Signing iOS Apps Example
A project I recently worked on had a reasonably complicated build process. The app was initially planned to be an enterprise app distributed over MDM. The app required FDA approval as a medical device, so strict Software Validation Testing (SVT) was needed. Our requirements were that SVT needs to be performed on a build that was as close as possible to the production version, and pre-release versions needed to have no possibility of being accidentally deployed to the field. We decided to use separate app identifiers for pre-release and production versions while having both apps use the same executable.
To do this, we took a copy of the production app and replaced the app identifier, provisioning, entitlements, and code signature with that of the pre-release app.
The re-signing process for this project has expanded to generate apps for App Store distribution, alter app icons and other image assets, alter embedded content such as video files, rewrite metadata, and renew the enterprise signing provisioning — all while only compiling the application code once.
Why Use Re-Signing Instead of Recompiling?
The main reason to re-signing iOS apps instead of just recompiling the source code is that having an identical executable is guaranteed. As small of a chance as it may be, there’s always the possibility that the source code or dependencies were modified between compiling. Re-signing can also be done without the source code and takes less time than recompiling.
Categories Included in the Re-Signing Process
An IPA file is an output of an Xcode build that contains everything needed to run your iOS app. The IPA can be uploaded to the App Store, or loaded onto devices through iTunes or an MDM solution. The signing bundled in the app determines which ways the app is allowed to be distributed. Despite being a finished product, an IPA file is not immutable.
IPA files are actually .zip archives. Upon unzipping the archive, you’ll find a .app application file. Viewing the package contents of this file reveals a directory of files that fall into one of several categories:
- Executable – a binary file that contains all of the compiled application code. This is the only object in the archive that should not be modified.
- Metadata – stored in the Info.plist file, and includes information such as version numbers, the bundle identifier, and the app’s display name.
- UI Assets – nib and storyboard files that define UI layouts and the
.carassets catalog files. These can be altered or replaced, but doing so is a delicate process since they generally are linked directly to the executable binary. Broken links to UI Assets will crash the application if not handled correctly. Other UI assets include catalogs and app icons.
- Embedded Content – videos and documents in the applications that are accessed as files. These can be replaced more freely than UI Assets since the executable only uses the file path and type to open the file.
Another type of embedded content that can be added or modified are frameworks. This is generally unnecessary. However, I once ran across an issue when using the QT cross-platform SDK, where the Frameworks our app depended on stopped getting bundled into the app during QT’s multistage compilation process for iOS apps. Manually adding these frameworks to the application contents and updating their signing solved the issue.
- Provisioning and Code Signing – Provisioning Profile and Code Signature files are used by the App Store and iOS to validate the app. The Code Signature is used to confirm the source and content integrity of the app. The provisioning profile is used to link the app’s unique identifier to the Code Signature, validating that the source is allowed to distribute an app with this identifier.
The Code Signature will need to be replaced if any of the application’s contents are modified. This can be done using the
codesignCLI tool included in the Xcode Command Line Tools bundle.
To sign the app as a different application, the app identifier in the Info.plist needs to be changed. The app will also require a new provisioning profile that matches the new app identifier. An entitlements.plist file will need to be created containing the new app identifier and then used in the call to the
codesignCLI to sign the app with the certificate identity matching the provisioning profile.
Applying the Re-Signing Process to Your iOS App
Interested in trying this process for yourself? I’ve included a script that will follow the process outlined above to take an existing IPA file, change its app identifier, load the new provisioning profile, sign the application and zip it back into an ipa file.
The script requires:
- An existing IPA file (that you have the rights to modify)
- A new app identifier,
- A distribution provisioning profile for the new app identifier installed on your computer
- The required signing certificate and private key in your keychain
Then, run the script and provide:
- The path to the IPA File
- The new app identifier (including Team ID)
- The name of the Certificate to sign with.
The script will create a new IPA in the current working directory and name it with the new identifier.
I hope that this post has helped you to gain a better understanding of the re-signing process and the anatomy of iOS apps, and how they can be manipulated to improve your processes.
To access the script, please visit GitHub.